diff --git a/.circleci/config.yml b/.circleci/config.yml index 6d691087dd..dc3b6382ae 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -150,13 +150,7 @@ jobs: - packages/instantsearch.js/dist - packages/react-instantsearch/dist - packages/react-instantsearch-core/dist - - packages/react-instantsearch-dom/dist - - packages/react-instantsearch-dom-maps/dist - - packages/react-instantsearch-native/dist - - packages/react-instantsearch-hooks/dist - - packages/react-instantsearch-hooks-web/dist - - packages/react-instantsearch-hooks-router-nextjs/dist - - packages/react-instantsearch-hooks-server/dist + - packages/react-instantsearch-router-nextjs/dist - packages/vue-instantsearch/vue2 - packages/vue-instantsearch/vue3 diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index 63bdb294e1..03ffbfc08e 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -2,17 +2,14 @@ "sandboxes": [ "instantsearchjs-es-template-pcw1k", "github/algolia/instantsearch.js/tree/templates/react-instantsearch", - "/examples/react-hooks/default-theme", + "/examples/react/default-theme", "/examples/vue/default-theme" ], "buildCommand": "build --no-private --ignore *-maps --ignore *-native", "packages": [ "packages/instantsearch.js", + "packages/react-instantsearch", "packages/react-instantsearch-core", - "packages/react-instantsearch-dom", - "packages/react-instantsearch-hooks", - "packages/react-instantsearch-hooks-web", - "packages/react-instantsearch-hooks-server", "packages/vue-instantsearch", "packages/instantsearch.css" ], diff --git a/.eslintignore b/.eslintignore index 73aed5b1bd..5c6e52ee58 100644 --- a/.eslintignore +++ b/.eslintignore @@ -21,9 +21,9 @@ coverage # Non-lintable source files ## React-Native TypeScript wasn't supporting the mix of react 18 and 17 -examples/react-hooks/react-native +examples/react/react-native ## Excluded from global typescript config -examples/react-hooks/next/next-env.d.ts +examples/react/next/next-env.d.ts ## templates that don't get installed packages/create-instantsearch-app/src/templates ## test fixtures for codemods diff --git a/.eslintrc.js b/.eslintrc.js index b2faaa6001..07617403a0 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -122,14 +122,7 @@ const config = { caseInsensitive: true, }, 'newlines-between': 'always', - groups: [ - 'builtin', - 'external', - 'parent', - 'sibling', - 'index', - 'type', - ], + groups: ['builtin', 'external', 'parent', 'sibling', 'index', 'type'], pathGroups: [ { pattern: '@/**/*', @@ -200,8 +193,8 @@ const config = { }, { files: [ - 'packages/react-instantsearch-hooks/**/*', - 'packages/react-instantsearch-hooks-*/**/*', + 'packages/react-instantsearch/**/*', + 'packages/react-instantsearch-*/**/*', ], rules: { '@typescript-eslint/consistent-type-assertions': 'off', @@ -250,25 +243,6 @@ const config = { }, }, // Disable stricter rules introduced for the next versions of the libraries. - { - files: [ - 'packages/react-instantsearch-core/**/*', - 'packages/react-instantsearch-dom/**/*', - ], - rules: { - '@typescript-eslint/consistent-type-assertions': 'off', - '@typescript-eslint/ban-types': 'off', - }, - }, - { - files: [ - 'examples/react-hooks/react-native/**/*.ts', - 'examples/react-hooks/react-native/**/*.tsx', - ], - parserOptions: { - project: 'examples/react-hooks/react-native/tsconfig.json', - }, - }, { files: [ 'packages/instantsearch.js/src/**/*.ts', @@ -373,12 +347,9 @@ const config = { }, }, { - files: [ - 'packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/**/*', - ], + files: ['packages/react-instantsearch-router-nextjs/__tests__/e2e/**/*'], parserOptions: { - project: - 'packages/react-instantsearch-hooks-router-nextjs/tsconfig.json', + project: 'packages/react-instantsearch-router-nextjs/tsconfig.json', }, }, { diff --git a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml index f0f7083648..5a818ea6e2 100644 --- a/.github/ISSUE_TEMPLATE/BUG_REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG_REPORT.yml @@ -36,7 +36,6 @@ body: Sandboxes InstantSearch.js React InstantSearch - React InstantSearch Hooks Vue InstantSearch Angular InstantSearch diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 45823c294f..a3c25ce9ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -127,15 +127,8 @@ Here are the main files and folders of the project. ``` ▸ examples/ << Examples, grouped per flavor ▸ packages/ << Packages of the project - ▸ react-instantsearch/ << Bundled React InstantSearch library - ▸ react-instantsearch-core/ << Runtime-independent React InstantSearch version - ▸ react-instantsearch-dom/ << DOM-specific React InstantSearch version - ▸ react-instantsearch-native/ << React Native-specific InstantSearch version - ▸ react-instantsearch-dom-maps/ << DOM-specific React InstantSearch version with Google Maps - - ▸ react-instantsearch-hooks/ << React InstantSearch Hooks library - ▸ react-instantsearch-hooks-web/ << DOM-specific React InstantSearch Hooks version - ▸ react-instantsearch-hooks-server/ << Server-specific React InstantSearch Hooks version + ▸ react-instantsearch/ << Bundled React InstantSearch library + ▸ react-instantsearch-core/ << Runtime-independent React InstantSearch version ▸ instantsearch.js/ << The InstantSearch.js library ▸ tests/ << The test utilites @@ -163,7 +156,7 @@ This monorepo has as goal to be used for all InstantSearch flavors and tools. To 8. replace commit messages which refer to issues/PRs with #xxx by also referencing the original repo: `git filter-branch --msg-filter 'sed -E "s/(#[[:digit:]]+)/algolia\/myproject\1/"' master..feat/import-myproject` 9. make any changes necessary to make the project work in the monorepo and commit those 10. make a pull request and _merge using rebase or merge_ (if you merge using squash the history will be lost) -11. manually tag and push the latest release commit from the imported project to let shipjs know which version to take into account during the next release process +11. manually tag and push the latest release commit from the imported project to let shipjs know which version to take into account during the next release process ## Tests @@ -171,7 +164,7 @@ The general philosophy of testing in InstantSearch follows [Testing Library's gu >The more your tests resemble the way your software is used, the more confidence they can give you. -We rely on [Jest](https://jestjs.io/) for unit tests on all flavors of InstantSearch. In addition, [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) is used to test interactions in React InstantSearch Hooks. +We rely on [Jest](https://jestjs.io/) for unit tests on all flavors of InstantSearch. In addition, [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/) is used to test interactions in React InstantSearch. ### How to write a test diff --git a/README.md b/README.md index d1c9d6c55f..b5ec2ccf84 100644 --- a/README.md +++ b/README.md @@ -44,14 +44,8 @@ It is part of the InstantSearch family which is designed for different platforms | [`create-instantsearch-app`](packages/create-instantsearch-app) | [![create-instantsearch-app npm version](https://img.shields.io/npm/v/create-instantsearch-app.svg?style=flat-square)](https://npmjs.org/package/create-instantsearch-app) | Command-line utility to quickly bootstrap a project with InstantSearch | | [`instantsearch.css`](packages/instantsearch.css) | [![instantsearch.css npm version](https://img.shields.io/npm/v/instantsearch.css.svg?style=flat-square)](https://npmjs.org/package/instantsearch.css) | Default CSS themes for InstantSearch | | [`instantsearch.js`](packages/instantsearch.js) | [![instantsearch.js npm version](https://img.shields.io/npm/v/instantsearch.js.svg?style=flat-square)](https://npmjs.org/package/instantsearch.js) | InstantSearch.js | -| [`react-instantsearch`](packages/react-instantsearch) | [![react-instantsearch npm version](https://img.shields.io/npm/v/react-instantsearch.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch)| React InstantSearch (prefer using `react-instantsearch-hooks-web` instead) | -| [`react-instantsearch-core`](packages/react-instantsearch-core) | [![react-instantsearch-core npm version](https://img.shields.io/npm/v/react-instantsearch-core.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-core) | React InstantSearch Core (prefer using `react-instantsearch-hooks` instead) | -| [`react-instantsearch-dom`](packages/react-instantsearch-dom) | [![react-instantsearch-dom npm version](https://img.shields.io/npm/v/react-instantsearch-dom.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-dom) | React InstantSearch DOM (prefer using `react-instantsearch-hooks-web` instead) | -| [`react-instantsearch-dom-maps`](packages/react-instantsearch-dom-maps) | [![react-instantsearch-dom-maps npm version](https://img.shields.io/npm/v/react-instantsearch-dom-maps.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-dom-maps)| GeoSearch widget for React InstantSearch DOM | -| [`react-instantsearch-hooks`](packages/react-instantsearch-hooks) | [![react-instantsearch-hooks npm version](https://img.shields.io/npm/v/react-instantsearch-hooks?style=flat-square)](https://npmjs.org/package/react-instantsearch-hooks) | React InstantSearch Hooks | -| [`react-instantsearch-hooks-server`](packages/react-instantsearch-hooks-server) | [![react-instantsearch-hooks-server npm version](https://img.shields.io/npm/v/react-instantsearch-hooks-server.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-hooks-server) | Utilities to do server-side rendering with React InstantSearch Hooks | -| [`react-instantsearch-hooks-web`](packages/react-instantsearch-hooks-web) | [![react-instantsearch-hooks-web npm version](https://img.shields.io/npm/v/react-instantsearch-hooks-web.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-hooks-web) | React InstantSearch Hooks bundled with UI components | -| [`react-instantsearch-native`](packages/react-instantsearch-native) | [![react-instantsearch-native npm version](https://img.shields.io/npm/v/react-instantsearch-native.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-native) | React InstantSearch Native (prefer using `react-instantsearch-hooks` instead) | +| [`react-instantsearch`](packages/react-instantsearch) | [![react-instantsearch npm version](https://img.shields.io/npm/v/react-instantsearch.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch)| React InstantSearch bundled library | +| [`react-instantsearch-core`](packages/react-instantsearch-core) | [![react-instantsearch-core npm version](https://img.shields.io/npm/v/react-instantsearch-core.svg?style=flat-square)](https://npmjs.org/package/react-instantsearch-core) | Runtime-independent React InstantSearch version | | [`vue-instantsearch`](packages/vue-instantsearch) | [![vue-instantsearch npm version](https://img.shields.io/npm/v/vue-instantsearch.svg?style=flat-square)](https://npmjs.org/package/vue-instantsearch) | Vue InstantSearch | ## Contributing @@ -68,7 +62,7 @@ To start contributing to code, you need to: 1. [Fork the project](https://help.github.com/articles/fork-a-repo/) 1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) 1. Install the dependencies: `yarn` -1. [Pick a package to work on](#packages) and cd into it (e.g. `cd packages/react-instantsearch-hooks`) +1. [Pick a package to work on](#packages) and cd into it (e.g. `cd packages/react-instantsearch`) Please read [our contribution process](CONTRIBUTING.md) to learn more. @@ -87,7 +81,7 @@ InstantSearch is [MIT licensed][license-url]. [algolia-website]: https://www.algolia.com/?utm_source=instantsearch.js&utm_campaign=repository "Algolia's website" [instantsearch-docs]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/?utm_source=instantsearch.js&utm_campaign=repository "InstantSearch.js documentation" -[react-instantsearch-docs]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/?utm_source=instantsearch.js&utm_campaign=repository "React InstantSearch documentation" +[react-instantsearch-docs]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/?utm_source=instantsearch.js&utm_campaign=repository "React InstantSearch documentation" [vue-instantsearch-docs]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/vue/?utm_source=instantsearch.js&utm_campaign=repository "Vue InstantSearch documentation" [angular-instantsearch-docs]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/angular/?utm_source=instantsearch.js&utm_campaign=repository "Angular InstantSearch documentation" [instantsearch-android-github]: https://github.com/algolia/instantsearch-android diff --git a/babel.config.js b/babel.config.js index c07aace4b9..114bb8d518 100644 --- a/babel.config.js +++ b/babel.config.js @@ -119,13 +119,6 @@ module.exports = (api) => { ], ], }, - { - test: 'packages/react-instantsearch-dom-maps', - plugins: clean([ - '@babel/plugin-syntax-dynamic-import', - !isRollup && 'babel-plugin-dynamic-import-node', - ]), - }, ], // jsx is transpiled, so the comment should no longer be present in the final files shouldPrintComment: (value) => value !== '* @jsx h ', diff --git a/bundlesize.config.json b/bundlesize.config.json index 4b8dfb8540..8d83809581 100644 --- a/bundlesize.config.json +++ b/bundlesize.config.json @@ -16,38 +16,14 @@ "path": "./packages/instantsearch.js/dist/instantsearch.development.js", "maxSize": "165 kB" }, - { - "path": "packages/react-instantsearch/dist/umd/Core.min.js", - "maxSize": "3.50 kB" - }, - { - "path": "packages/react-instantsearch/dist/umd/Connectors.min.js", - "maxSize": "26 kB" - }, - { - "path": "packages/react-instantsearch/dist/umd/Dom.min.js", - "maxSize": "44.50 kB" - }, { "path": "packages/react-instantsearch-core/dist/umd/ReactInstantSearchCore.min.js", - "maxSize": "29.50 kB" - }, - { - "path": "packages/react-instantsearch-hooks/dist/umd/ReactInstantSearchHooks.min.js", "maxSize": "46.25 kB" }, { - "path": "packages/react-instantsearch-hooks-web/dist/umd/ReactInstantSearchHooksDOM.min.js", + "path": "packages/react-instantsearch/dist/umd/ReactInstantSearch.min.js", "maxSize": "56 kB" }, - { - "path": "packages/react-instantsearch-dom/dist/umd/ReactInstantSearchDOM.min.js", - "maxSize": "44.75 kB" - }, - { - "path": "packages/react-instantsearch-dom-maps/dist/umd/ReactInstantSearchDOMMaps.min.js", - "maxSize": "7.25 kB" - }, { "path": "packages/vue-instantsearch/vue2/umd/index.js", "maxSize": "63 kB" diff --git a/examples/react-hooks/default-theme/index.html b/examples/react-hooks/default-theme/index.html deleted file mode 100644 index 536b79cc4e..0000000000 --- a/examples/react-hooks/default-theme/index.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - React InstantSearch - Hooks - - - - - -
- - - - - diff --git a/examples/react-hooks/default-theme/package.json b/examples/react-hooks/default-theme/package.json deleted file mode 100644 index 44055a11b4..0000000000 --- a/examples/react-hooks/default-theme/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example-react-instantsearch-hooks-default-theme", - "version": "6.50.0", - "private": true, - "scripts": { - "build": "BABEL_ENV=parcel parcel build index.html", - "start": "BABEL_ENV=parcel parcel index.html" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.js": "4.56.8", - "react": "18.1.0", - "react-dom": "18.1.0", - "react-instantsearch-hooks-web": "6.47.3" - }, - "devDependencies": { - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "typescript": "5.1.3" - } -} diff --git a/examples/react-hooks/e-commerce/App.css b/examples/react-hooks/e-commerce/App.css deleted file mode 100644 index b426e86e8e..0000000000 --- a/examples/react-hooks/e-commerce/App.css +++ /dev/null @@ -1,341 +0,0 @@ -* { - box-sizing: border-box; -} - -body, -h1, -h2 { - margin: 0; - padding: 0; -} - -body { - font-family: Open Sans, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, - Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', - 'Segoe UI Symbol'; - -webkit-font-smoothing: antialiased; -} - -h2 { - color: #21243d; - font-family: Hind, sans-serif; - font-size: 1.5rem; - font-weight: bold; -} - -/* Header */ - -.header { - align-items: center; - background: linear-gradient(to bottom, #fbc300, #c98a00); - background-image: url('./assets/cover.png'); - background-image: url('./assets/cover.png'), - linear-gradient(to bottom, #fbc300, #c98a00); - background-position: center; - background-size: cover; - color: #fff; - display: flex; - flex-direction: column; - justify-content: center; - min-height: 368px; - padding: 0.5rem 1rem; - text-align: center; -} - -.header-logo { - margin: 0; -} - -.header-logo svg { - height: 24px; - width: 92px; -} - -.header-title { - font-size: 38px; - font-weight: 300; -} - -/* Containers */ - -.container { - display: flex; - margin: 0 auto; - max-width: 1300px; - padding: 2rem 1rem; -} - -.container-filters { - flex: 1; - margin-right: 60px; - max-width: 260px; -} - -.container-header { - align-items: center; - display: flex; - justify-content: space-between; - min-height: 80px; -} - -.container-results { - flex: 3; -} - -.container-options { - border-bottom: 1px solid #ebecf3; - display: flex; - justify-content: flex-end; - margin-bottom: 30px; - padding: 30px 0; -} - -.container-options .container-option:not(:first-child) { - margin-left: 48px; -} - -.container-options select { - min-width: 100px; -} - -.container-footer { - margin: 4rem 0; -} - -/* Styles the SFFV highlightings */ - -em { - font-style: normal; -} - -em, -mark { - background: rgba(226, 164, 0, 0.4); -} - -/* Clear refinements container */ - -.clear-filters { - align-items: center; - display: flex; -} - -.clear-filters svg { - margin-right: 8px; -} - -/* Panel */ - -.container-body .ais-Panel { - border-top: 1px solid #ebecf3; - padding-bottom: 2rem; - padding-top: 2rem; -} - -.ais-Panel-header { - font-family: Hind, sans-serif; -} - -/* Search box */ - -.header .ais-SearchBox { - height: 64px; - width: 740px; -} - -.header .ais-SearchBox .ais-SearchBox-input { - background-color: #fff; - border-radius: 8px; - box-shadow: 0 4px 48px 0 rgba(0, 0, 0, 0.2); - font-family: Hind, sans-serif; - height: 64px; - /* - The "Hind" font family is vertically off-balance. - Adding 4px of padding top makes it more vertically aligned. - */ - padding: 4px 48px 0 64px; -} - -.header .ais-SearchBox-submit { - padding: 0 1rem 0 2rem; - width: 64px; -} - -.header .ais-SearchBox .ais-SearchBox-input::placeholder { - color: rgba(33, 36, 61, 0.24); - opacity: 1; /* Firefox */ -} - -.ais-SearchBox-input:-ms-input-placeholder { - color: rgba(33, 36, 61, 0.24); -} - -.ais-SearchBox-input::-ms-input-placeholder { - color: rgba(33, 36, 61, 0.24); -} - -.ais-SearchBox-submit { - color: #e2a400; -} - -.ais-RefinementList .ais-SearchBox-input { - font-family: Hind, sans-serif; - /* - The "Hind" font family is vertically off-balance. - Adding some padding top makes it more vertically aligned. - */ - padding-top: 2px; -} - -/* Hits */ - -.hit { - color: #21243d; - font-size: 14px; - line-height: 18px; -} - -.hit h1 { - font-size: 14px; -} - -.hit-category { - color: #21243d; - font-size: 12px; - font-weight: 600; - line-height: 1; - margin-bottom: 8px; - opacity: 0.7; - text-transform: uppercase; -} - -.hit-description { - margin-top: 2px; -} - -.hit-info-container { - overflow-wrap: break-word; - word-break: break-word; -} - -.hit-image-container { - align-items: center; - display: flex; - height: 174px; - justify-content: center; - margin: auto; - width: 174px; -} - -.hit-image { - height: auto; - max-height: 100%; - max-width: 100%; -} - -.hit-em { - color: #e2a400; - font-size: 11px; - font-weight: 600; -} - -.hit-rating { - border: 1px solid rgba(226, 164, 0, 0.5); - border-radius: 4px; - margin-left: 4px; - padding: 0 4px; -} - -.hits-empty-state { - align-items: center; - display: flex; - flex-direction: column; - margin: auto; - max-width: 300px; -} - -.hits-empty-state-title { - font-family: Hind; - font-size: 1.5rem; - font-weight: bold; - margin-bottom: 0; - text-align: center; -} - -.hits-empty-state-description { - color: rgba(35, 37, 51, 0.6); - font-size: 0.875rem; - text-align: center; -} - -.hits-empty-state .ais-ClearRefinements { - margin-top: 1rem; -} - -.hits-empty-state .ais-ClearRefinements-button--disabled { - display: none; -} - -.hits-empty-state .ais-ClearRefinements-button { - background: rgba(10, 8, 41, 0.04); - border-radius: 3px; - color: #21243d; - min-height: 48px; - padding: 16px 24px; -} - -/* ToggleRefinement */ - -.ais-ToggleRefinement-label { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; -} - -.ais-ToggleRefinement-checkbox { - font: inherit; - margin-left: 1rem; - margin-right: 0; - position: relative; -} - -.ais-ToggleRefinement-checkbox:checked::before { - color: #e2a400; -} - -.ais-ToggleRefinement-checkbox::before { - align-items: center; - color: rgba(33, 36, 61, 0.32); - content: 'No'; - display: flex; - font-size: 0.8rem; - height: 16px; - position: absolute; - right: 38px; -} - -.ais-ToggleRefinement-checkbox:checked::before { - content: 'Yes'; -} - -.ais-ToggleRefinement-count { - display: none; -} - -/* RatingMenu */ - -.ais-RatingMenu-item:not(.ais-RatingMenu-item--selected) { - opacity: 0.5; -} - -.ais-RatingMenu-starIcon { - margin-right: 0.5rem; -} - -/* Hide all mobile-specific design on desktop */ - -@media (min-width: 900px) { - [data-layout='mobile'] { - display: none; - } -} diff --git a/examples/react-hooks/e-commerce/App.mobile.css b/examples/react-hooks/e-commerce/App.mobile.css deleted file mode 100644 index 339c08cbc7..0000000000 --- a/examples/react-hooks/e-commerce/App.mobile.css +++ /dev/null @@ -1,264 +0,0 @@ -@media (max-width: 899px) { - /* Filters overlay */ - - .container-filters { - background: #fff; - border-radius: 16px; - left: 0; - max-width: initial; - padding-bottom: 4rem; - position: fixed; - top: 0; - transform: translateY(120vh); - transition: transform 300ms cubic-bezier(0.465, 0.183, 0.153, 0.946); - width: 100%; - will-change: transform; - z-index: 1; - } - - .container-filters .container-header, - .container-filters .container-body { - padding: 2rem 2rem 0 2rem; - } - - .filtering .header { - /* - Closing panel on outter click didn't work on mobile safari. - This is one of the workarounds from the following: - https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event#Safari_Mobile - */ - cursor: pointer; - } - - .filtering .header-logo { - left: 50%; - pointer-events: none; - position: absolute; - top: 1.5rem; - transform: translateX(-50%); - } - - .filtering .header-title, - .filtering .container-results, - .container-filters-footer { - display: none; - } - - .filtering .container-filters { - position: absolute; - transform: translateY(4rem); - } - - .filtering .container-filters-footer { - background-color: #fff; - border-top: 1px solid #ebecf3; - bottom: 0; - display: flex; - justify-content: space-between; - margin: 0 -2rem; - padding: 1rem; - position: fixed; - width: 100%; - z-index: 5; /* avoid collision with slider UI */ - } - - .container-filters-footer-button-wrapper { - width: calc(50% - 0.5rem); - } - - .container-filters-footer .ais-ClearRefinements-button, - .container-filters-footer .button { - background-color: rgba(65, 66, 71, 0.08); - border: none; - border-radius: 8px; - cursor: pointer; - display: flex; - font: inherit; - font-size: 0.75rem; - font-weight: bold; - justify-content: center; - padding: 12px; - text-align: center; - width: 100%; - } - - .container-filters-footer .button-primary { - background-color: #e2a400; - color: #fff; - } - - /* Filters button that triggers the overlay */ - - .filtering .filters-button { - display: none; - } - - .filters-button { - align-items: center; - background-color: #e2a400; - border: none; - border-radius: 8px; - bottom: 2rem; - box-shadow: 0 4px 22px 0 rgba(185, 135, 0, 0.5); - color: #fff; - cursor: pointer; - display: flex; - font: inherit; - font-size: 0.875rem; - font-weight: bold; - justify-content: center; - left: 50%; - min-height: 40px; - min-width: 112px; - position: fixed; - transform: translateX(-50%); - } - - .filters-button svg { - height: 14px; - margin-right: 8px; - width: 16px; - } - - .container { - padding: 4rem 2rem; - } - - .container-options { - display: none; - } - - .header { - background: linear-gradient(to bottom, #ae8600, #885b01); - background-image: url('./assets/cover-mobile.png'); - background-image: url('./assets/cover-mobile.png'), - linear-gradient(to bottom, #ae8600, #885b01); - background-position: bottom; - background-size: cover; - min-height: 300px; - position: relative; - transition: transform 200ms ease-out; - } - - /* SearchBox */ - - .header .ais-SearchBox { - bottom: 0; - left: 0; - position: absolute; - transform: translateY(50%); - width: 100vw; - } - - .header .ais-SearchBox .ais-SearchBox-form { - margin: auto; - max-width: 90%; - } - - .ais-SearchBox .ais-SearchBox-input, - .ais-RefinementList .ais-SearchBox-input { - font-size: 1rem; - } - - .ais-RefinementList .ais-SearchBox-input { - min-height: 48px; - } - - /* RefinementList */ - - .ais-RefinementList-list { - display: grid; - grid-auto-flow: column; - grid-gap: 0 2rem; - grid-template-rows: repeat(5, 1fr); - } - - .ais-RefinementList-item { - flex: 50%; - } - - .ais-RefinementList-checkbox { - height: 1.5rem; - min-width: 1.5rem; - } - - .ais-RefinementList-item--selected .ais-RefinementList-checkbox::after { - align-items: center; - background: none; - content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' width='12' height='9'%3E%3Cdefs%3E%3Cpath id='a' d='M0 0h24v24H0z'/%3E%3C/defs%3E%3Cg fill='none' fill-rule='evenodd' transform='translate(-6 -8)'%3E%3Cmask id='b' fill='%23fff'%3E%3Cuse xlink:href='%23a'/%3E%3C/mask%3E%3Cpath fill='%23fff' fill-rule='nonzero' d='M16.5 8.5L18 10l-6.99 7-4.51-4.5L8 11l3.01 3z' mask='url(%23b)'/%3E%3C/g%3E%3C/svg%3E"); - display: flex; - height: 100%; - justify-content: center; - left: initial; - position: relative; - top: initial; - transform: initial; - width: initial; - } - - /* HierarchicalMenu */ - - .ais-HierarchicalMenu-link::before { - background-color: rgba(65, 66, 71, 0.08); - border-radius: 50%; - padding: 8px; - } - - /* ToggleRefinement */ - - .ais-ToggleRefinement-checkbox { - min-width: 47px; - position: relative; - } - - .ais-ToggleRefinement-checkbox { - margin-left: 2rem; - } - - .ais-ToggleRefinement-checkbox::after { - height: 1.5rem; - top: -4px; - width: 1.5rem; - } - - .ais-ToggleRefinement-checkbox::before { - right: 54px; - } - - /* RatingMenu */ - - .ais-RatingMenu-starIcon { - height: 1.5rem; - margin-right: 1rem; - width: 1.5rem; - } - - /* Hits */ - - .ais-Hits-list { - grid-gap: 1rem; - } - - .hit { - display: flex; - } - - .hit-image-container { - flex: 1; - margin-right: 2rem; - } - - .hit-info-container { - flex: 2; - } - - .hits-empty-state-image { - display: none; - } - - /* Hide all desktop-specific design on mobile */ - - [data-layout='desktop'] { - display: none; - } -} diff --git a/examples/react-hooks/e-commerce/Theme.css b/examples/react-hooks/e-commerce/Theme.css deleted file mode 100644 index 263d67f06d..0000000000 --- a/examples/react-hooks/e-commerce/Theme.css +++ /dev/null @@ -1,544 +0,0 @@ -/* Global */ - -[class^='ais-'] { - box-sizing: border-box; - font-size: 0.9rem; -} - -a[class^='ais-'] { - color: #21243d; - text-decoration: none; -} - -/* - We need to target the root element because Angular InstantSearch - creates web components which are not targetable with the `*` selector. -*/ -[class^='ais-'][class$='--disabled'], -/* - We need to target all elements for widgets containing - multiple sub elements (e.g. RangeSlider) -*/ -[class^='ais-'][class$='--disabled'] * { - cursor: not-allowed; -} - -.ais-Breadcrumb, -.ais-ClearRefinements, -.ais-CurrentRefinements, -.ais-ClearRefinements-button, -.ais-GeoSearch, -.ais-HierarchicalMenu, -.ais-Hits, -.ais-Results, -.ais-HitsPerPage, -.ais-ResultsPerPage, -.ais-InfiniteHits, -.ais-InfiniteResults, -.ais-Menu, -.ais-MenuSelect, -.ais-NumericMenu, -.ais-NumericSelector, -.ais-Pagination, -.ais-Panel, -.ais-PoweredBy, -.ais-RangeInput, -.ais-RangeSlider, -.ais-RatingMenu, -.ais-RefinementList, -.ais-SearchBox, -.ais-SortBy, -.ais-SortBy-select, -.ais-HitsPerPage-select, -.ais-Stats, -.ais-ToggleRefinement { - color: #21243d; - font-size: 0.75rem; -} - -/* Highlighting */ - -.ais-Highlight-highlighted, -.ais-Snippet-highlighted { - background: rgba(226, 164, 0, 0.4); -} - -/* Hits */ - -.ais-Hits-list { - display: grid; - grid-gap: 40px; - grid-template-columns: 1fr; -} - -@media (min-width: 680px) { - .ais-Hits-list { - grid-template-columns: 1fr 1fr; - } -} - -@media (min-width: 900px) { - .ais-Hits-list { - grid-template-columns: 1fr 1fr 1fr; - } -} - -@media (min-width: 1200px) { - .ais-Hits-list { - grid-template-columns: 1fr 1fr 1fr 1fr; - } -} - -/* Menus */ - -.ais-RefinementList-item, -.ais-Menu-item, -.ais-HierarchicalMenu-item, -.ais-RatingMenu-item { - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.ais-RefinementList-item, -/* - The refinement list item in InstantSearch.js contains a wrapping `div` because of - the template behavior. We therefore need to apply the styles to all the elements - in a refinement list. -*/ -.ais-RefinementList-item *, -.ais-RatingMenu-item { - cursor: pointer; -} - -.ais-HierarchicalMenu-link, -.ais-RatingMenu-item, -.ais-RefinementList-item { - padding-bottom: 1rem; -} - -.ais-Breadcrumb-item--selected, -.ais-HierarchicalMenu-item--selected, -.ais-Menu-item--selected { - font-weight: bold; -} - -.ais-RatingMenu-starIcon--full { - fill: #e2a400; -} - -.ais-RatingMenu-starIcon--empty { - fill: rgba(0, 0, 0, 0.08); -} - -/* Panel */ - -.ais-Panel--collapsible { - position: relative; -} - -.ais-Panel--collapsed .ais-Panel-body, -.ais-Panel--collapsed .ais-Panel-footer { - display: none; -} - -.ais-Panel-collapseButton { - background: none; - border: none; - cursor: pointer; - padding: 0; - position: absolute; - right: 0; -} - -.ais-Panel-header { - border: none; - color: #21243d; - font-size: 0.678rem; - font-weight: 600; - letter-spacing: 0.08rem; - line-height: 1.6; - padding-bottom: 1rem; - text-transform: uppercase; -} - -/* Search box */ - -.ais-SearchBox-form { - position: relative; -} - -.ais-SearchBox-input { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: rgba(65, 66, 71, 0.06); - border: none; - border-radius: 3px; - color: rgba(33, 36, 61, 0.8); - font-family: inherit; - min-height: 54px; - outline: none; - padding-left: 56px; - width: 100%; -} - -.ais-SearchBox-input::placeholder { - color: rgba(33, 36, 61, 0.5); - opacity: 1; /* Firefox */ -} - -.ais-SearchBox-input:-ms-input-placeholder { - color: rgba(33, 36, 61, 0.5); -} - -.ais-SearchBox-input::-ms-input-placeholder { - color: rgba(33, 36, 61, 0.5); -} - -.ais-SearchBox-reset, -.ais-SearchBox-loadingIndicator, -.ais-SearchBox-submit { - align-items: center; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - display: flex; - height: 100%; - justify-content: center; - position: absolute; - top: 50%; - transform: translateY(-50%); - width: 48px; -} - -.ais-SearchBox-reset[hidden], -.ais-SearchBox-loadingIndicator[hidden] { - display: none; -} - -.ais-SearchBox-submit { - left: 0; -} - -.ais-SearchBox-reset, -.ais-SearchBox-loadingIndicator { - right: 0; -} - -.ais-SearchBox-resetIcon { - height: 10px; - width: 10px; -} - -/* SFFV search box */ - -.ais-RefinementList .ais-SearchBox-input { - border-radius: 3px; - color: rgba(33, 36, 61, 0.8); - font-size: 0.8rem; - min-height: 40px; - padding: 0 44px; -} - -.ais-RefinementList .ais-SearchBox-form { - margin-bottom: 1rem; -} - -/* Menus */ - -.ais-HierarchicalMenu-link, -.ais-RatingMenu-link, -.ais-RefinementList-label { - align-items: center; - display: flex; -} - -.ais-RefinementList-checkbox { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: rgba(65, 66, 71, 0.08); - border: none; - border-radius: 2px; - height: 1rem; - margin: 0; - margin-right: 1rem; - position: relative; - width: 1rem; -} - -.ais-RefinementList-item--selected { - font-weight: bold; -} - -.ais-RefinementList-item--selected .ais-RefinementList-checkbox { - background-color: #e2a400; -} - -.ais-RefinementList-item--selected .ais-RefinementList-checkbox::after { - background-color: #fff; - border-radius: 4px; - content: ''; - height: 4px; - left: 50%; - position: absolute; - top: 50%; - transform: translateX(-2px) translateY(-2px); - width: 4px; -} - -.ais-HierarchicalMenu-count, -.ais-Menu-count, -.ais-RefinementList-count, -.ais-ToggleRefinement-count, -.ais-RatingMenu-count { - align-items: center; - background-color: rgba(65, 66, 71, 0.08); - border-radius: 4px; - color: rgba(33, 36, 61, 0.8); - display: flex; - font-size: 0.64rem; - font-weight: 600; - letter-spacing: 1.1px; - margin-left: 8px; - padding: 0 4px; -} - -.ais-HierarchicalMenu-showMore, -.ais-Menu-showMore, -.ais-RefinementList-showMore { - margin-top: 1rem; -} - -.ais-HierarchicalMenu-list { - font-weight: normal; -} - -.ais-HierarchicalMenu-link::before { - align-items: center; - content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8' viewBox='0 0 8 8'%3E%3Cpath fill='%2390919E' fill-rule='nonzero' d='M0 4l4-4 4 4z'/%3E%3C/svg%3E%0A"); - display: flex; - height: 8px; - justify-content: center; - margin-right: 1rem; - width: 8px; -} - -.ais-HierarchicalMenu-item--selected .ais-HierarchicalMenu-link::before { - transform: rotate(180deg); -} - -.ais-HierarchicalMenu-item--selected - .ais-HierarchicalMenu-item:not(.ais-HierarchicalMenu-item--selected) - .ais-HierarchicalMenu-link::before { - transform: rotate(0); -} - -/* ClearRefinements */ - -.ais-ClearRefinements, -.ais-ClearRefinements-button { - color: rgba(33, 36, 61, 0.7); -} - -.ais-ClearRefinements-button--disabled { - color: rgba(33, 36, 61, 0.5); -} - -/* ToggleRefinement */ - -.ais-ToggleRefinement-label { - cursor: pointer; - display: flex; -} - -.ais-ToggleRefinement-checkbox { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background: rgba(65, 66, 71, 0.08); - border: none; - border-radius: 8px; - cursor: pointer; - height: 16px; - margin-right: 16px; - min-width: 30px; - transition: background 150ms ease-out; -} - -.ais-ToggleRefinement-checkbox:checked { - background: #e2a400; -} - -.ais-ToggleRefinement-checkbox::after { - background-image: linear-gradient(to top, #f5f5fa, #fff); - border-radius: 100%; - box-shadow: 0 4px 11px 0 rgba(37, 44, 97, 0.15), - 0 2px 3px 0 rgba(93, 100, 148, 0.2); - content: ''; - height: 16px; - position: absolute; - transition: transform 150ms ease-out; - width: 16px; -} - -.ais-ToggleRefinement-checkbox:checked::after { - transform: translateX(100%); -} - -/* Selectors */ - -.ais-SortBy, -.ais-HitsPerPage { - position: relative; -} - -.ais-SortBy::after, -.ais-HitsPerPage::after { - content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='7' viewBox='0 0 12 7'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cpath d='M14-5v16H-2V-5z'/%3E%3Cpath fill='%23000' stroke='%23FFF' stroke-width='.5' d='M2.228 1.332a.664.664 0 0 0-.942.001.665.665 0 0 0-.002.941l4.247 4.247c.259.26.679.26.938 0l4.247-4.247a.664.664 0 0 0-.002-.94.666.666 0 0 0-.942-.002L6 5.105 2.228 1.332z'/%3E%3C/g%3E%3C/svg%3E%0A"); - display: inline-block; -} - -.ais-SortBy-select, -.ais-HitsPerPage-select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background: none; - border: none; - color: #21243d; - font-family: inherit; -} - -/* Sliders */ - -.ais-RangeSlider .rheostat-horizontal { - cursor: pointer; - width: calc(100% - 10px); -} - -.ais-RangeSlider .rheostat-background { - background-color: rgba(65, 66, 71, 0.08); - border: none; - border-radius: 3px; - height: 3px; -} - -.ais-RangeSlider .rheostat-progress { - background-color: #e2a400; - border-radius: 3px; - height: 3px; - top: 0; -} - -.ais-RangeSlider .rheostat-tooltip { - font-weight: bold; - -moz-user-select: none; - -webkit-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.ais-RangeSlider .rheostat-handle { - background-image: linear-gradient(to top, #f5f5fa, #fff); - border: none; - box-shadow: 0 4px 11px 0 rgba(37, 44, 97, 0.15), - 0 2px 3px 0 rgba(93, 100, 148, 0.2); - margin-left: -5px; - top: -9px; -} - -.ais-RangeSlider .rheostat-marker { - background-color: rgba(65, 66, 71, 0.08); -} - -/* RangeInput */ - -.ais-RangeInput-input { - background: none; - border: none; - border-bottom: 1px solid #ebecf3; - color: #21243d; - font-family: inherit; - font-size: 0.875rem; - font-weight: 600; - min-width: none; - padding: 0; - padding-bottom: 3px; -} - -.ais-RangeInput-label:first-of-type { - margin-right: 6px; -} - -.ais-RangeInput-label:last-of-type { - margin-left: 6px; -} - -/* Pagination */ - -.ais-Pagination-list { - justify-content: center; -} - -.ais-Pagination-item, -.ais-Pagination-link { - align-items: center; - display: flex; - justify-content: center; -} - -.ais-Pagination-item { - height: 38px; - width: 38px; -} - -.ais-Pagination-item { - background-color: rgba(65, 66, 71, 0.08); - border-radius: 4px; - color: #414247; -} - -.ais-Pagination-item--selected { - background-color: #e2a400; - background-image: linear-gradient( - to bottom, - rgba(255, 255, 255, 0.34), - rgba(255, 255, 255, 0) - ); - font-weight: bold; -} - -.ais-Pagination-item--firstPage, -.ais-Pagination-item--previousPage, -.ais-Pagination-item--nextPage, -.ais-Pagination-item--lastPage { - background: none; -} - -.ais-Pagination-item--disabled { - opacity: 0.33; -} - -.ais-Pagination-item--selected a { - color: #fff; -} - -.ais-Pagination-item.ais-Pagination-item--page { - margin-right: 4px; -} - -.ais-Pagination-item.ais-Pagination-item--previousPage { - margin-right: 1rem; -} - -.ais-Pagination-item.ais-Pagination-item--nextPage { - margin-left: calc(1rem - 4px); -} - -.ais-Pagination-link { - height: 100%; - width: 100%; -} diff --git a/examples/react-hooks/e-commerce/assets/cover-mobile.png b/examples/react-hooks/e-commerce/assets/cover-mobile.png deleted file mode 100755 index 0692219458..0000000000 Binary files a/examples/react-hooks/e-commerce/assets/cover-mobile.png and /dev/null differ diff --git a/examples/react-hooks/e-commerce/assets/cover.png b/examples/react-hooks/e-commerce/assets/cover.png deleted file mode 100755 index 0487aa31c9..0000000000 Binary files a/examples/react-hooks/e-commerce/assets/cover.png and /dev/null differ diff --git a/examples/react-hooks/e-commerce/assets/favicon.png b/examples/react-hooks/e-commerce/assets/favicon.png deleted file mode 100644 index b9cee152b2..0000000000 Binary files a/examples/react-hooks/e-commerce/assets/favicon.png and /dev/null differ diff --git a/examples/react-hooks/e-commerce/assets/manifest.webmanifest b/examples/react-hooks/e-commerce/assets/manifest.webmanifest deleted file mode 100644 index 44df3f507f..0000000000 --- a/examples/react-hooks/e-commerce/assets/manifest.webmanifest +++ /dev/null @@ -1,15 +0,0 @@ -{ - "short_name": "E-commerce", - "name": "React InstantSearch Hooks E-commerce Demo", - "icons": [ - { - "src": "favicon.png", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - } - ], - "start_url": "../index.html", - "display": "standalone", - "theme_color": "#e2a400", - "background_color": "#fff" -} diff --git a/examples/react-hooks/e-commerce/index.html b/examples/react-hooks/e-commerce/index.html deleted file mode 100644 index 99f84643df..0000000000 --- a/examples/react-hooks/e-commerce/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - React InstantSearch Hooks - e-commerce - - - - - -
- - - - - diff --git a/examples/react-hooks/e-commerce/package.json b/examples/react-hooks/e-commerce/package.json deleted file mode 100644 index 93dde9d812..0000000000 --- a/examples/react-hooks/e-commerce/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "example-react-instantsearch-hooks-e-commerce", - "version": "6.38.26", - "private": true, - "scripts": { - "build": "BABEL_ENV=parcel parcel build index.html", - "website:examples": "BABEL_ENV=parcel parcel build index.html --public-url . --dist-dir=../../../website/examples/react-hooks/e-commerce", - "start": "BABEL_ENV=parcel parcel index.html" - }, - "browserslist": "firefox 68, chrome 78, IE 11", - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.js": "4.56.8", - "react": "18.1.0", - "react-compound-slider": "3.4.0", - "react-dom": "18.1.0", - "react-instantsearch-hooks-web": "6.47.3" - }, - "devDependencies": { - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "typescript": "5.1.3" - } -} diff --git a/examples/react-hooks/getting-started/.editorconfig b/examples/react-hooks/getting-started/.editorconfig deleted file mode 100644 index dd7255e8a4..0000000000 --- a/examples/react-hooks/getting-started/.editorconfig +++ /dev/null @@ -1,8 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true diff --git a/examples/react-hooks/getting-started/.gitignore b/examples/react-hooks/getting-started/.gitignore deleted file mode 100644 index bf78c5a78c..0000000000 --- a/examples/react-hooks/getting-started/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -pnpm-debug.log* -lerna-debug.log* - -node_modules -dist -.parcel-cache -*.local - -# Editor directories and files -.vscode -.idea -.DS_Store -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? diff --git a/examples/react-hooks/getting-started/README.md b/examples/react-hooks/getting-started/README.md deleted file mode 100644 index b8c281d6af..0000000000 --- a/examples/react-hooks/getting-started/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# react-instantsearch-hooks-app - -[![Edit getting-started](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/getting-started) - -_This project was generated with [create-instantsearch-app](https://github.com/algolia/instantsearch/tree/master/packages/create-instantsearch-app) by [Algolia](https://algolia.com)._ - -## Get started - -To run this project locally, install the dependencies and run the local server: - -```sh -npm install -npm start -``` - -Alternatively, you may use [Yarn](https://http://yarnpkg.com/): - -```sh -yarn -yarn start -``` - -Open http://localhost:3000 to see your app. diff --git a/examples/react-hooks/getting-started/favicon.png b/examples/react-hooks/getting-started/favicon.png deleted file mode 100644 index b9cee152b2..0000000000 Binary files a/examples/react-hooks/getting-started/favicon.png and /dev/null differ diff --git a/examples/react-hooks/getting-started/index.html b/examples/react-hooks/getting-started/index.html deleted file mode 100644 index eb7fc92b0d..0000000000 --- a/examples/react-hooks/getting-started/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - React InstantSearch Hooks — Getting started - - - - - -
- - - - - diff --git a/examples/react-hooks/getting-started/package.json b/examples/react-hooks/getting-started/package.json deleted file mode 100644 index 539c08b6a1..0000000000 --- a/examples/react-hooks/getting-started/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "example-react-instantsearch-hooks-getting-started", - "version": "6.38.26", - "private": true, - "scripts": { - "build": "BABEL_ENV=parcel parcel build index.html", - "start": "BABEL_ENV=parcel parcel index.html --port 3000" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.js": "4.56.8", - "react": "18.1.0", - "react-dom": "18.1.0", - "react-instantsearch-hooks-web": "6.47.3" - }, - "devDependencies": { - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "typescript": "5.1.3" - } -} diff --git a/examples/react-hooks/getting-started/src/App.css b/examples/react-hooks/getting-started/src/App.css deleted file mode 100644 index e01152732c..0000000000 --- a/examples/react-hooks/getting-started/src/App.css +++ /dev/null @@ -1,71 +0,0 @@ -body, -h1 { - margin: 0; - padding: 0; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} - -em { - background: cyan; - font-style: normal; -} - -.header { - display: flex; - align-items: center; - min-height: 50px; - padding: 0.5rem 1rem; - background-image: linear-gradient(to right, #8e43e7, #00aeff); - color: #fff; - margin-bottom: 1rem; -} - -.header a { - color: #fff; - text-decoration: none; -} - -.header-title { - font-size: 1.2rem; - font-weight: normal; -} - -.header-title::after { - content: ' ▸ '; - padding: 0 0.5rem; -} - -.header-subtitle { - font-size: 1.2rem; -} - -.container { - max-width: 1200px; - margin: 0 auto; - padding: 1rem; -} - -.search-panel { - display: flex; -} - -.search-panel__filters { - flex: 1; -} - -.search-panel__results { - flex: 3; -} - -.searchbox { - margin-bottom: 2rem; -} - -.pagination { - margin: 2rem auto; - text-align: center; -} diff --git a/examples/react-hooks/next-routing/README.md b/examples/react-hooks/next-routing/README.md deleted file mode 100644 index ceb90aca59..0000000000 --- a/examples/react-hooks/next-routing/README.md +++ /dev/null @@ -1,18 +0,0 @@ -This example shows how to do server side rendering with next.js and React InstantSearch Hooks. There's a live example here: https://codesandbox.io/s/github/algolia/instantsearch.js/tree/master/examples/react-hooks/next. - -[![Edit next-routing](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/next-routing) - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react-hooks/next-routing -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn run dev -``` - -Read more about React InstantSearch Hooks [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/). diff --git a/examples/react-hooks/next-routing/package.json b/examples/react-hooks/next-routing/package.json deleted file mode 100644 index 3e5fbbea3a..0000000000 --- a/examples/react-hooks/next-routing/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "example-react-instantsearch-hooks-next-routing-example", - "version": "6.57.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.css": "8.0.0", - "next": "12.1.6", - "react": "18.1.0", - "react-dom": "18.1.0", - "react-instantsearch-hooks-router-nextjs": "6.47.3", - "react-instantsearch-hooks-server": "6.47.3", - "react-instantsearch-hooks-web": "6.47.3" - }, - "devDependencies": { - "@types/node": "17.0.40", - "@types/react": "18.0.12", - "eslint": "8.4.0", - "eslint-config-next": "12.0.7", - "typescript": "5.1.3" - } -} diff --git a/examples/react-hooks/next/.gitignore b/examples/react-hooks/next/.gitignore deleted file mode 100644 index 1437c53f70..0000000000 --- a/examples/react-hooks/next/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env.local -.env.development.local -.env.test.local -.env.production.local - -# vercel -.vercel diff --git a/examples/react-hooks/next/README.md b/examples/react-hooks/next/README.md deleted file mode 100644 index 6cfc3f11f4..0000000000 --- a/examples/react-hooks/next/README.md +++ /dev/null @@ -1,18 +0,0 @@ -This example shows how to do server side rendering with next.js and React InstantSearch Hooks. There's a live example here: https://codesandbox.io/s/github/algolia/instantsearch.js/tree/master/examples/react-hooks/next. - -[![Edit next](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/next) - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react-hooks/next -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn run dev -``` - -Read more about React InstantSearch Hooks [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/). diff --git a/examples/react-hooks/react-native/.expo-shared/assets.json b/examples/react-hooks/react-native/.expo-shared/assets.json deleted file mode 100644 index 1e6decfbb5..0000000000 --- a/examples/react-hooks/react-native/.expo-shared/assets.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, - "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true -} diff --git a/examples/react-hooks/react-native/.gitignore b/examples/react-hooks/react-native/.gitignore deleted file mode 100644 index ec8a36a257..0000000000 --- a/examples/react-hooks/react-native/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -node_modules/ -.expo/ -dist/ -npm-debug.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision -*.orig.* -web-build/ - -# macOS -.DS_Store diff --git a/examples/react-hooks/react-native/README.md b/examples/react-hooks/react-native/README.md deleted file mode 100644 index b1e4d46e5e..0000000000 --- a/examples/react-hooks/react-native/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# React InstantSearch Hooks with React Native - -[![Edit react-native](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/react-native) - -This example shows how to use React InstantSearch Hooks with React Native. - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react-hooks/react-native -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn run start -``` - -Read more about React InstantSearch Hooks [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/). diff --git a/examples/react-hooks/react-native/app.json b/examples/react-hooks/react-native/app.json deleted file mode 100644 index 476db9aec0..0000000000 --- a/examples/react-hooks/react-native/app.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "expo": { - "name": "ais-ecommerce-demo-app", - "slug": "ais-ecommerce-demo-app", - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/icon.png", - "splash": { - "image": "./assets/splash.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff" - }, - "updates": { - "fallbackToCacheTimeout": 0 - }, - "assetBundlePatterns": ["**/*"], - "ios": { - "supportsTablet": true - }, - "android": { - "adaptiveIcon": { - "foregroundImage": "./assets/adaptive-icon.png", - "backgroundColor": "#FFFFFF" - } - }, - "web": { - "favicon": "./assets/favicon.png" - } - } -} diff --git a/examples/react-hooks/react-native/assets/icon.png b/examples/react-hooks/react-native/assets/icon.png deleted file mode 100644 index a0b1526fc7..0000000000 Binary files a/examples/react-hooks/react-native/assets/icon.png and /dev/null differ diff --git a/examples/react-hooks/react-native/assets/splash.png b/examples/react-hooks/react-native/assets/splash.png deleted file mode 100644 index 0e89705a94..0000000000 Binary files a/examples/react-hooks/react-native/assets/splash.png and /dev/null differ diff --git a/examples/react-hooks/react-native/babel.config.js b/examples/react-hooks/react-native/babel.config.js deleted file mode 100644 index 9d89e13119..0000000000 --- a/examples/react-hooks/react-native/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function (api) { - api.cache(true); - return { - presets: ['babel-preset-expo'], - }; -}; diff --git a/examples/react-hooks/react-native/package.json b/examples/react-hooks/react-native/package.json deleted file mode 100644 index 6e312a4a7d..0000000000 --- a/examples/react-hooks/react-native/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "example-react-instantsearch-hooks-react-native-example", - "version": "6.38.26", - "private": true, - "main": "node_modules/expo/AppEntry.js", - "scripts": { - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", - "eject": "expo eject" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "expo": "~44.0.0", - "expo-status-bar": "~1.2.0", - "instantsearch.js": "4.56.8", - "react": "17.0.1", - "react-instantsearch-hooks": "6.47.3", - "react-native": "0.64.3", - "react-native-web": "0.17.1" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@types/react": "~17.0.21", - "@types/react-native": "~0.64.12", - "expo-cli": "5.1.1", - "typescript": "5.1.3" - } -} diff --git a/examples/react/autocomplete/README.md b/examples/react/autocomplete/README.md deleted file mode 100644 index 5be6d0b715..0000000000 --- a/examples/react/autocomplete/README.md +++ /dev/null @@ -1,26 +0,0 @@ -This example shows how to use an external autocomplete component with `react-instantsearch` - -[![Edit autocomplete](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/autocomplete) - -It uses [react-autosuggest](https://github.com/moroshko/react-autosuggest) as the autocomplete external component. - -You will find two use cases: - -* How to build an autocomplete displaying hits from different indices -* How to build @-mentions using [ant](https://ant.design) as the external component - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/autocomplete -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn start -``` - - -Read more about `react-instantsearch` [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react/autocomplete/__mocks__/styleMock.js b/examples/react/autocomplete/__mocks__/styleMock.js deleted file mode 100644 index 33c8d29dc0..0000000000 --- a/examples/react/autocomplete/__mocks__/styleMock.js +++ /dev/null @@ -1,2 +0,0 @@ -// eslint-disable-next-line import/no-commonjs -module.exports = {}; diff --git a/examples/react/autocomplete/index.html b/examples/react/autocomplete/index.html deleted file mode 100644 index 9840f70f1c..0000000000 --- a/examples/react/autocomplete/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - autocomplete with react-instantsearch - - - - -

Autocomplete targeting multiple indices

-
-

Autocomplete of mentions

-
- - - - diff --git a/examples/react/autocomplete/package.json b/examples/react/autocomplete/package.json deleted file mode 100644 index df7cdab63d..0000000000 --- a/examples/react/autocomplete/package.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "name": "example-react-instantsearch-autocomplete", - "version": "17.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "BABEL_ENV=parcel parcel index.html --port 3000", - "build": "BABEL_ENV=parcel parcel build index.html --public-url .", - "test": "jest --ci" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "react-test-renderer": "17.0.2" - }, - "jest": { - "transform": { - "^.+\\.(jsx?|tsx?)$": [ - "babel-jest", - { - "rootMode": "upward" - } - ] - }, - "moduleNameMapper": { - "\\.css$": "/__mocks__/styleMock.js" - } - }, - "dependencies": { - "algoliasearch": "4.14.3", - "antd": "3.23.2", - "prop-types": "15.6.2", - "react": "17.0.2", - "react-autosuggest": "9.4.3", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/examples/react/autocomplete/src/App-Mentions.js b/examples/react/autocomplete/src/App-Mentions.js deleted file mode 100644 index 07a57c17d7..0000000000 --- a/examples/react/autocomplete/src/App-Mentions.js +++ /dev/null @@ -1,37 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import Mention from 'antd/lib/mention'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { InstantSearch, connectAutoComplete } from 'react-instantsearch-dom'; -import 'antd/lib/mention/style/css'; - -const AsyncMention = ({ hits, refine }) => ( - hit.name)} - onSearchChange={(query) => refine(query)} - /> -); - -AsyncMention.propTypes = { - hits: PropTypes.array, - refine: PropTypes.func, -}; - -const ConnectedAsyncMention = connectAutoComplete(AsyncMention); - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = () => ( - - - -); - -export default App; diff --git a/examples/react/autocomplete/src/App-Multi-Index.js b/examples/react/autocomplete/src/App-Multi-Index.js deleted file mode 100644 index 0cd95dd6a9..0000000000 --- a/examples/react/autocomplete/src/App-Multi-Index.js +++ /dev/null @@ -1,96 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import Autosuggest from 'react-autosuggest'; -import { - InstantSearch, - Configure, - Index, - Highlight, - connectAutoComplete, -} from 'react-instantsearch-dom'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = () => ( - - - - - - -); - -class Example extends Component { - static propTypes = { - hits: PropTypes.arrayOf(PropTypes.object).isRequired, - currentRefinement: PropTypes.string.isRequired, - refine: PropTypes.func.isRequired, - }; - - state = { - value: this.props.currentRefinement, - }; - - onChange = (event, { newValue }) => { - this.setState({ - value: newValue, - }); - }; - - onSuggestionsFetchRequested = ({ value }) => { - this.props.refine(value); - }; - - onSuggestionsClearRequested = () => { - this.props.refine(); - }; - - getSuggestionValue(hit) { - return hit.name; - } - - renderSuggestion(hit) { - return ; - } - - renderSectionTitle(section) { - return section.index; - } - - getSectionSuggestions(section) { - return section.hits; - } - - render() { - const { hits } = this.props; - const { value } = this.state; - - const inputProps = { - placeholder: 'Search for a product...', - onChange: this.onChange, - value, - }; - - return ( - - ); - } -} - -const AutoComplete = connectAutoComplete(Example); - -export default App; diff --git a/examples/react/autocomplete/src/__tests__/App.test.js b/examples/react/autocomplete/src/__tests__/App.test.js deleted file mode 100644 index c6470d4b94..0000000000 --- a/examples/react/autocomplete/src/__tests__/App.test.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Mentions from '../App-Mentions'; -import MultiIndex from '../App-Multi-Index'; - -jest.mock('antd/lib/mention', () => { - return ({ placeholder, suggestions }) => - ` - ${placeholder} - ${suggestions.join('\n')} -`; -}); - -describe('autocomplete recipe', () => { - it('MultiIndex renders without crashing', () => { - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); - it('Mentions renders without crashing', () => { - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react/autocomplete/src/__tests__/__snapshots__/App.test.js.snap b/examples/react/autocomplete/src/__tests__/__snapshots__/App.test.js.snap deleted file mode 100644 index b8a405221d..0000000000 --- a/examples/react/autocomplete/src/__tests__/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,38 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`autocomplete recipe Mentions renders without crashing 1`] = ` -" - give someone an @-mention here - -" -`; - -exports[`autocomplete recipe MultiIndex renders without crashing 1`] = ` -
- -
-
-`; diff --git a/examples/react/autocomplete/src/index.js b/examples/react/autocomplete/src/index.js deleted file mode 100644 index 7ee36842af..0000000000 --- a/examples/react/autocomplete/src/index.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import Mentions from './App-Mentions'; -import App from './App-Multi-Index'; - -ReactDOM.render( - , - document.getElementById('autocomplete-with-multi-indices') -); - -ReactDOM.render(, document.getElementById('autocomplete-mentions')); diff --git a/examples/react/autocomplete/src/style.css b/examples/react/autocomplete/src/style.css deleted file mode 100644 index c1b2bebe8d..0000000000 --- a/examples/react/autocomplete/src/style.css +++ /dev/null @@ -1,115 +0,0 @@ -body { - font-family: Helvetica, sans-serif; - margin: 0; - padding: 1em; - box-sizing: border-box; -} - -.highlighted { - background: yellow; -} - -.autocomplete { - display: flex; - justify-content: space-between; - border: 1px solid red; -} - -.content { - display: flex; - justify-content: space-between; -} - -.block { - padding: 5px 10px; -} - -.title { - border: 1px solid red; - display: flex; - justify-content: space-around; - padding: 5px 10px; -} - -.disabled { - display: none; -} - -.ais-MultiIndex__root { - width: 100%; -} - -.title div { - width: 100%; - padding: 5px 10px; -} - -.react-autosuggest__container { - position: relative; -} - -.react-autosuggest__input { - width: 600px; - height: 30px; - padding: 10px 20px; - font-family: Helvetica, sans-serif; - font-weight: 300; - font-size: 16px; - border: 1px solid #aaa; - border-radius: 4px; -} - -.react-autosuggest__input:focus { - outline: none; -} - -.react-autosuggest__container--open .react-autosuggest__input { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -.react-autosuggest__suggestions-container { - display: none; -} - -.react-autosuggest__container--open .react-autosuggest__suggestions-container { - display: block; - position: absolute; - top: 51px; - width: 640px; - border: 1px solid #aaa; - background-color: #fff; - font-family: Helvetica, sans-serif; - font-weight: 300; - font-size: 16px; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; - z-index: 2; -} - -.react-autosuggest__suggestions-list { - margin: 0; - padding: 0; - list-style-type: none; -} - -.react-autosuggest__suggestion { - cursor: pointer; - padding: 10px 20px; -} - -.react-autosuggest__suggestion--focused { - background-color: #ddd; -} - -.react-autosuggest__section-title { - padding: 10px 0 0 10px; - font-size: 12px; - color: #777; - border-top: 1px dashed #ccc; -} - -.react-autosuggest__section-container:first-child - .react-autosuggest__section-title { - border-top: 0; -} diff --git a/examples/react/default-theme/App.css b/examples/react/default-theme/App.css deleted file mode 100644 index 07cd77aa72..0000000000 --- a/examples/react/default-theme/App.css +++ /dev/null @@ -1,84 +0,0 @@ -* { - box-sizing: border-box; -} - -html, -body { - margin: 0; - padding: 0; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} - -header.header { - display: flex; - align-items: center; - z-index: 99; - padding-top: 56px; - width: 100%; - padding: 10px; - background: #222f3f; -} - -header.header .is-logo { - float: left; - margin-right: 12px; -} - -header.header .logo { - display: block; -} - -aside, -.results-wrapper { - padding: 10px; -} - -.thank-you { - font-size: 12px; - text-align: center; - margin-top: 20px; -} - -.ais-Panel { - margin-top: 20px; -} - -.content-wrapper { - display: flex; -} - -.results-topbar { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 10px; -} - -.sort-by { - display: flex; - align-items: center; -} - -.sort-by label { - margin-right: 5px; -} - -footer { - margin-top: 25px; -} - -.results-wrapper { - width: 100%; -} - -.no-results { - text-align: center; -} - -.no-results .query { - font-style: italic; -} diff --git a/examples/react/default-theme/App.js b/examples/react/default-theme/App.js deleted file mode 100644 index 48ad38bbc5..0000000000 --- a/examples/react/default-theme/App.js +++ /dev/null @@ -1,171 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import React from 'react'; -import { - InstantSearch, - Hits, - HierarchicalMenu, - RefinementList, - SearchBox, - SortBy, - Stats, - Pagination, - Panel, - ClearRefinements, - RatingMenu, - RangeInput, - Highlight, - Configure, - connectStateResults, -} from 'react-instantsearch-dom'; - -import withURLSync from './URLSync'; -import './App.css'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = (props) => ( - - -
-
- - -
- -); - -const Header = () => ( -
- - React InstantSearch - - -
-); - -const Facets = () => ( - -); - -const Hit = ({ hit }) => { - const icons = []; - for (let i = 0; i < 5; i++) { - const suffixClassName = i >= hit.rating ? '--empty' : ''; - const suffixXlink = i >= hit.rating ? 'Empty' : ''; - - icons.push( - - ); - } - - return ( -
-
-
- -
-
- -
-
-
{icons}
-
${hit.price}
-
-
-
- ); -}; - -const CustomResults = connectStateResults(({ searchState, searchResults }) => ( -
-
- -
- - -
-
- - {searchResults && searchResults.nbHits ? ( -
- -
- -
-
- ) : ( -
- No results found matching " - {searchState.query} - " -
- )} -
-)); - -export default withURLSync(App); diff --git a/examples/react/default-theme/URLSync.js b/examples/react/default-theme/URLSync.js deleted file mode 100644 index 1eaa103822..0000000000 --- a/examples/react/default-theme/URLSync.js +++ /dev/null @@ -1,56 +0,0 @@ -import qs from 'qs'; -import React, { Component } from 'react'; - -const updateAfter = 700; -const searchStateToURL = (searchState) => - searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : ''; - -const withURLSync = (App) => - class WithURLSync extends Component { - state = { - searchState: qs.parse(window.location.search.slice(1)), - }; - - componentDidMount() { - window.addEventListener('popstate', this.onPopState); - } - - componentWillUnmount() { - clearTimeout(this.debouncedSetState); - window.removeEventListener('popstate', this.onPopState); - } - - onPopState = ({ state }) => - this.setState({ - searchState: state || {}, - }); - - onSearchStateChange = (searchState) => { - clearTimeout(this.debouncedSetState); - - this.debouncedSetState = setTimeout(() => { - window.history.pushState( - searchState, - null, - searchStateToURL(searchState) - ); - }, updateAfter); - - this.setState({ searchState }); - }; - - render() { - const { searchState } = this.state; - - return ( - - ); - } - }; - -export default withURLSync; diff --git a/examples/react/default-theme/index.html b/examples/react/default-theme/index.html index 4151360b6e..ae3320db18 100644 --- a/examples/react/default-theme/index.html +++ b/examples/react/default-theme/index.html @@ -13,15 +13,18 @@ --> - React InstantSearch - Algolia theme + React InstantSearch
+ + + diff --git a/examples/react/default-theme/index.js b/examples/react/default-theme/index.js deleted file mode 100644 index ae31e41347..0000000000 --- a/examples/react/default-theme/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react/default-theme/package.json b/examples/react/default-theme/package.json index 454cf8d21c..1fffbd24ba 100644 --- a/examples/react/default-theme/package.json +++ b/examples/react/default-theme/package.json @@ -1,12 +1,23 @@ { "name": "example-react-instantsearch-default-theme", - "version": "15.0.0", + "version": "6.50.0", "private": true, + "scripts": { + "build": "BABEL_ENV=parcel parcel build index.html", + "start": "BABEL_ENV=parcel parcel index.html" + }, "dependencies": { "algoliasearch": "4.14.3", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" + "instantsearch.js": "4.56.8", + "react": "18.1.0", + "react-dom": "18.1.0", + "react-instantsearch": "6.47.3" + }, + "devDependencies": { + "@parcel/core": "2.8.0", + "@parcel/packager-raw-url": "2.8.0", + "@parcel/transformer-webmanifest": "2.8.0", + "parcel": "2.8.0", + "typescript": "5.1.3" } } diff --git a/examples/react-hooks/default-theme/src/App.css b/examples/react/default-theme/src/App.css similarity index 100% rename from examples/react-hooks/default-theme/src/App.css rename to examples/react/default-theme/src/App.css diff --git a/examples/react-hooks/default-theme/src/App.tsx b/examples/react/default-theme/src/App.tsx similarity index 99% rename from examples/react-hooks/default-theme/src/App.tsx rename to examples/react/default-theme/src/App.tsx index 996e779c6f..8da10a66ee 100644 --- a/examples/react-hooks/default-theme/src/App.tsx +++ b/examples/react/default-theme/src/App.tsx @@ -21,7 +21,7 @@ import { SearchBox, SortBy, ToggleRefinement, -} from 'react-instantsearch-hooks-web'; +} from 'react-instantsearch'; import { Panel, diff --git a/examples/react-hooks/default-theme/src/components/NumericMenu.tsx b/examples/react/default-theme/src/components/NumericMenu.tsx similarity index 98% rename from examples/react-hooks/default-theme/src/components/NumericMenu.tsx rename to examples/react/default-theme/src/components/NumericMenu.tsx index 657791b62a..4a79c8350e 100644 --- a/examples/react-hooks/default-theme/src/components/NumericMenu.tsx +++ b/examples/react/default-theme/src/components/NumericMenu.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useNumericMenu, UseNumericMenuProps } from 'react-instantsearch-hooks'; +import { useNumericMenu, UseNumericMenuProps } from 'react-instantsearch-core'; import { cx } from '../cx'; diff --git a/examples/react-hooks/default-theme/src/components/Panel.tsx b/examples/react/default-theme/src/components/Panel.tsx similarity index 100% rename from examples/react-hooks/default-theme/src/components/Panel.tsx rename to examples/react/default-theme/src/components/Panel.tsx diff --git a/examples/react-hooks/default-theme/src/components/QueryRuleContext.tsx b/examples/react/default-theme/src/components/QueryRuleContext.tsx similarity index 95% rename from examples/react-hooks/default-theme/src/components/QueryRuleContext.tsx rename to examples/react/default-theme/src/components/QueryRuleContext.tsx index cce4c9ec0c..939d252074 100644 --- a/examples/react-hooks/default-theme/src/components/QueryRuleContext.tsx +++ b/examples/react/default-theme/src/components/QueryRuleContext.tsx @@ -1,4 +1,4 @@ -import { useQueryRules, UseQueryRulesProps } from 'react-instantsearch-hooks'; +import { useQueryRules, UseQueryRulesProps } from 'react-instantsearch-core'; export type QueryRuleContextProps = Partial< Pick diff --git a/examples/react-hooks/default-theme/src/components/QueryRuleCustomData.tsx b/examples/react/default-theme/src/components/QueryRuleCustomData.tsx similarity index 97% rename from examples/react-hooks/default-theme/src/components/QueryRuleCustomData.tsx rename to examples/react/default-theme/src/components/QueryRuleCustomData.tsx index 9364db9f48..06689d047a 100644 --- a/examples/react-hooks/default-theme/src/components/QueryRuleCustomData.tsx +++ b/examples/react/default-theme/src/components/QueryRuleCustomData.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useQueryRules, UseQueryRulesProps } from 'react-instantsearch-hooks'; +import { useQueryRules, UseQueryRulesProps } from 'react-instantsearch-core'; import { cx } from '../cx'; diff --git a/examples/react-hooks/default-theme/src/components/Refresh.css b/examples/react/default-theme/src/components/Refresh.css similarity index 100% rename from examples/react-hooks/default-theme/src/components/Refresh.css rename to examples/react/default-theme/src/components/Refresh.css diff --git a/examples/react-hooks/default-theme/src/components/Refresh.tsx b/examples/react/default-theme/src/components/Refresh.tsx similarity index 91% rename from examples/react-hooks/default-theme/src/components/Refresh.tsx rename to examples/react/default-theme/src/components/Refresh.tsx index cda6889874..fc271f8177 100644 --- a/examples/react-hooks/default-theme/src/components/Refresh.tsx +++ b/examples/react/default-theme/src/components/Refresh.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; import './Refresh.css'; export function Refresh() { diff --git a/examples/react-hooks/default-theme/src/components/index.ts b/examples/react/default-theme/src/components/index.ts similarity index 100% rename from examples/react-hooks/default-theme/src/components/index.ts rename to examples/react/default-theme/src/components/index.ts diff --git a/examples/react-hooks/default-theme/src/components/layout/Tabs.css b/examples/react/default-theme/src/components/layout/Tabs.css similarity index 100% rename from examples/react-hooks/default-theme/src/components/layout/Tabs.css rename to examples/react/default-theme/src/components/layout/Tabs.css diff --git a/examples/react-hooks/default-theme/src/components/layout/Tabs.tsx b/examples/react/default-theme/src/components/layout/Tabs.tsx similarity index 100% rename from examples/react-hooks/default-theme/src/components/layout/Tabs.tsx rename to examples/react/default-theme/src/components/layout/Tabs.tsx diff --git a/examples/react-hooks/default-theme/src/components/layout/index.tsx b/examples/react/default-theme/src/components/layout/index.tsx similarity index 100% rename from examples/react-hooks/default-theme/src/components/layout/index.tsx rename to examples/react/default-theme/src/components/layout/index.tsx diff --git a/examples/react-hooks/default-theme/src/cx.ts b/examples/react/default-theme/src/cx.ts similarity index 100% rename from examples/react-hooks/default-theme/src/cx.ts rename to examples/react/default-theme/src/cx.ts diff --git a/examples/react-hooks/default-theme/src/env.js b/examples/react/default-theme/src/env.js similarity index 100% rename from examples/react-hooks/default-theme/src/env.js rename to examples/react/default-theme/src/env.js diff --git a/examples/react-hooks/default-theme/src/index.tsx b/examples/react/default-theme/src/index.tsx similarity index 100% rename from examples/react-hooks/default-theme/src/index.tsx rename to examples/react/default-theme/src/index.tsx diff --git a/examples/react-hooks/default-theme/src/isModifierClick.ts b/examples/react/default-theme/src/isModifierClick.ts similarity index 100% rename from examples/react-hooks/default-theme/src/isModifierClick.ts rename to examples/react/default-theme/src/isModifierClick.ts diff --git a/examples/react/e-commerce/.editorconfig b/examples/react/e-commerce/.editorconfig deleted file mode 100644 index 9d08a1a828..0000000000 --- a/examples/react/e-commerce/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 2 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true diff --git a/examples/react/e-commerce/.gitignore b/examples/react/e-commerce/.gitignore deleted file mode 100644 index d30f40ef44..0000000000 --- a/examples/react/e-commerce/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. - -# dependencies -/node_modules - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/examples/react/e-commerce/.prettierrc b/examples/react/e-commerce/.prettierrc deleted file mode 100644 index 6e93c0d52f..0000000000 --- a/examples/react/e-commerce/.prettierrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "proseWrap": "never", - "singleQuote": true, - "trailingComma": "es5" -} diff --git a/examples/react/e-commerce/AlgoliaSvg.js b/examples/react/e-commerce/AlgoliaSvg.js deleted file mode 100644 index 1f03a35afe..0000000000 --- a/examples/react/e-commerce/AlgoliaSvg.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; - -const AlgoliaSvg = () => ( - - - - - -); - -export default AlgoliaSvg; diff --git a/examples/react/e-commerce/App.js b/examples/react/e-commerce/App.js deleted file mode 100644 index 4c9de7761d..0000000000 --- a/examples/react/e-commerce/App.js +++ /dev/null @@ -1,369 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import React, { useRef } from 'react'; -import { - InstantSearch, - HierarchicalMenu, - RefinementList, - SortBy, - Pagination, - ClearRefinements, - Highlight, - Hits, - HitsPerPage, - Panel, - Configure, - SearchBox, - Snippet, - ToggleRefinement, -} from 'react-instantsearch-dom'; - -import AlgoliaSvg from './AlgoliaSvg'; -import withURLSync from './URLSync'; -import { formatNumber } from './utils'; -import { - ClearFiltersMobile, - PriceSlider, - NoResults, - Ratings, - ResultsNumberMobile, - SaveFiltersMobile, -} from './widgets'; -import './Theme.css'; -import './App.css'; -import './App.mobile.css'; -import './widgets/Pagination.css'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const Hit = ({ hit }) => ( -
-
- {hit.name} -
- -
-

{hit.categories[0]}

-

- -

-

- -

- -
-

- ${' '} - {formatNumber(hit.price)}{' '} - - - - {' '} - {hit.rating} - -

-
-
-
-); - -const App = (props) => { - const containerRef = useRef(null); - const headerRef = useRef(null); - - function openFilters() { - document.body.classList.add('filtering'); - window.scrollTo(0, 0); - window.addEventListener('keyup', onKeyUp); - window.addEventListener('click', onClick); - } - - function closeFilters() { - document.body.classList.remove('filtering'); - containerRef.current.scrollIntoView(); - window.removeEventListener('keyup', onKeyUp); - window.removeEventListener('click', onClick); - } - - function onKeyUp(event) { - if (event.key !== 'Escape') { - return; - } - - closeFilters(); - } - - function onClick(event) { - if (event.target !== headerRef.current) { - return; - } - - closeFilters(); - } - - return ( - -
-

- -

- -

Stop looking for an item — find it.

- - - - - - - - } - /> -
- - - -
-
-
-
-

Filters

- -
- - - - - - - - Clear filters - - ), - }} - /> -
- -
- -
-
- -
- - - - - - - - - - - - - - - - - - - -
-
- -
-
- -
- -
- -
-
-
- -
-
- - - -
- - - - -
- - - - - - ), - next: ( - - - - - - ), - }} - /> -
-
-
- - -
- ); -}; - -export default withURLSync(App); diff --git a/examples/react-hooks/e-commerce/App.tsx b/examples/react/e-commerce/App.tsx similarity index 99% rename from examples/react-hooks/e-commerce/App.tsx rename to examples/react/e-commerce/App.tsx index ff287b8b7d..0d7731d495 100644 --- a/examples/react-hooks/e-commerce/App.tsx +++ b/examples/react/e-commerce/App.tsx @@ -13,7 +13,7 @@ import { ToggleRefinement, Highlight, Snippet, -} from 'react-instantsearch-hooks-web'; +} from 'react-instantsearch'; import { AlgoliaSvg, diff --git a/examples/react/e-commerce/URLSync.js b/examples/react/e-commerce/URLSync.js deleted file mode 100644 index 9c665209cf..0000000000 --- a/examples/react/e-commerce/URLSync.js +++ /dev/null @@ -1,263 +0,0 @@ -/* eslint-disable complexity */ - -import qs from 'qs'; -import React, { Component } from 'react'; - -const updateAfter = 700; - -const routeStateDefaultValues = { - query: '', - page: '1', - brands: undefined, - category: '', - rating: '', - price: '', - free_shipping: 'false', - sortBy: 'instant_search', - hitsPerPage: '20', -}; - -const encodedCategories = { - Cameras: 'Cameras & Camcorders', - Cars: 'Car Electronics & GPS', - Phones: 'Cell Phones', - TV: 'TV & Home Theater', -}; - -const decodedCategories = Object.keys(encodedCategories).reduce((acc, key) => { - const newKey = encodedCategories[key]; - const newValue = key; - - return { - ...acc, - [newKey]: newValue, - }; -}, {}); - -// Returns a slug from the category name. -// Spaces are replaced by "+" to make -// the URL easier to read and other -// characters are encoded. -function getCategorySlug(name) { - const encodedName = decodedCategories[name] || name; - - return encodedName - .replace(/ > /g, '/') - .split(' ') - .map(encodeURIComponent) - .join('+'); -} - -// Returns a name from the category slug. -// The "+" are replaced by spaces and other -// characters are decoded. -function getCategoryName(slug) { - const decodedSlug = encodedCategories[slug] || slug; - - return decodedSlug - .split('+') - .map(decodeURIComponent) - .join(' ') - .replace(/\//g, ' > '); -} - -const searchStateToURL = (searchState) => { - const routeState = { - query: searchState.query, - page: String(searchState.page), - brands: searchState.refinementList && searchState.refinementList.brand, - category: - searchState.hierarchicalMenu && - searchState.hierarchicalMenu['hierarchicalCategories.lvl0'], - rating: - searchState.range && - searchState.range.rating && - String(searchState.range.rating.min), - price: - searchState.range && - searchState.range.price && - `${searchState.range.price.min || ''}:${ - searchState.range.price.max || '' - }`, - free_shipping: - (searchState.toggle && String(searchState.toggle.free_shipping)) || - undefined, - sortBy: searchState.sortBy, - hitsPerPage: - (searchState.hitsPerPage && String(searchState.hitsPerPage)) || undefined, - }; - - const { protocol, hostname, port = '', pathname, hash } = location; - const portWithPrefix = port === '' ? '' : `:${port}`; - const urlParts = location.href.match(/^(.*?)\/search/); - const baseUrl = - (urlParts && urlParts[0]) || - `${protocol}//${hostname}${portWithPrefix}${pathname}search`; - - const categoryPath = routeState.category - ? `${getCategorySlug(routeState.category)}/` - : ''; - const queryParameters = {}; - - if (routeState.query && routeState.query !== routeStateDefaultValues.query) { - queryParameters.query = encodeURIComponent(routeState.query); - } - if (routeState.page && routeState.page !== routeStateDefaultValues.page) { - queryParameters.page = routeState.page; - } - if ( - routeState.brands && - routeState.brands !== routeStateDefaultValues.brands - ) { - queryParameters.brands = routeState.brands.map(encodeURIComponent); - } - if ( - routeState.rating && - routeState.rating !== routeStateDefaultValues.rating - ) { - queryParameters.rating = routeState.rating; - } - if (routeState.price && routeState.price !== routeStateDefaultValues.price) { - queryParameters.price = routeState.price; - } - if ( - routeState.free_shipping && - routeState.free_shipping !== routeStateDefaultValues.free_shipping - ) { - queryParameters.free_shipping = routeState.free_shipping; - } - if ( - routeState.sortBy && - routeState.sortBy !== routeStateDefaultValues.sortBy - ) { - queryParameters.sortBy = routeState.sortBy; - } - if ( - routeState.hitsPerPage && - routeState.hitsPerPage !== routeStateDefaultValues.hitsPerPage - ) { - queryParameters.hitsPerPage = routeState.hitsPerPage; - } - - const queryString = qs.stringify(queryParameters, { - addQueryPrefix: true, - arrayFormat: 'repeat', - }); - - return `${baseUrl}/${categoryPath}${queryString}${hash}`; -}; - -const urlToSearchState = (location) => { - const pathnameMatches = location.pathname.match(/search\/(.*?)\/?$/); - const category = getCategoryName( - (pathnameMatches && pathnameMatches[1]) || '' - ); - const queryParameters = qs.parse(location.search.slice(1)); - const { - query = '', - page = 1, - brands = [], - price, - free_shipping, - hitsPerPage, - sortBy, - rating, - } = queryParameters; - // `qs` does not return an array when there's a single value. - const allBrands = Array.isArray(brands) ? brands : [brands].filter(Boolean); - - const searchState = { range: {} }; - - if (query) { - searchState.query = decodeURIComponent(query); - } - if (page) { - searchState.page = page; - } - if (category) { - searchState.hierarchicalMenu = { - 'hierarchicalCategories.lvl0': category, - }; - } - if (allBrands.length) { - searchState.refinementList = { - brand: allBrands.map(decodeURIComponent), - }; - } - if (rating) { - searchState.range.rating = { - min: Number(rating), - }; - } - if (price) { - const [min, max = undefined] = price.split(':'); - searchState.range.price = { - min: min || undefined, - max: max || undefined, - }; - } - if (free_shipping) { - searchState.toggle = { - free_shipping: Boolean(free_shipping), - }; - } - if (sortBy) { - searchState.sortBy = sortBy; - } - - if (hitsPerPage) { - searchState.hitsPerPage = hitsPerPage; - } - - return searchState; -}; - -const withURLSync = (App) => - class WithURLSync extends Component { - state = { - searchState: urlToSearchState(window.location), - }; - - componentDidMount() { - window.addEventListener('popstate', this.onPopState); - } - - componentWillUnmount() { - clearTimeout(this.debouncedSetState); - window.removeEventListener('popstate', this.onPopState); - } - - onPopState = ({ state }) => - this.setState({ - searchState: state || {}, - }); - - onSearchStateChange = (searchState) => { - clearTimeout(this.debouncedSetState); - - this.debouncedSetState = setTimeout(() => { - window.history.pushState( - searchState, - null, - searchStateToURL(searchState) - ); - }, updateAfter); - - this.setState({ searchState }); - }; - - render() { - const { searchState } = this.state; - - return ( - - ); - } - }; - -export default withURLSync; diff --git a/examples/react-hooks/e-commerce/components/AlgoliaSvg.tsx b/examples/react/e-commerce/components/AlgoliaSvg.tsx similarity index 100% rename from examples/react-hooks/e-commerce/components/AlgoliaSvg.tsx rename to examples/react/e-commerce/components/AlgoliaSvg.tsx diff --git a/examples/react-hooks/e-commerce/components/ClearFilters.tsx b/examples/react/e-commerce/components/ClearFilters.tsx similarity index 94% rename from examples/react-hooks/e-commerce/components/ClearFilters.tsx rename to examples/react/e-commerce/components/ClearFilters.tsx index 4723f42e0d..2e002539c8 100644 --- a/examples/react-hooks/e-commerce/components/ClearFilters.tsx +++ b/examples/react/e-commerce/components/ClearFilters.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useClearRefinements } from 'react-instantsearch-hooks-web'; +import { useClearRefinements } from 'react-instantsearch'; export function ClearFilters() { const { refine, canRefine } = useClearRefinements(); diff --git a/examples/react-hooks/e-commerce/components/ClearFiltersMobile.tsx b/examples/react/e-commerce/components/ClearFiltersMobile.tsx similarity index 87% rename from examples/react-hooks/e-commerce/components/ClearFiltersMobile.tsx rename to examples/react/e-commerce/components/ClearFiltersMobile.tsx index ead29ce6f5..849730d197 100644 --- a/examples/react-hooks/e-commerce/components/ClearFiltersMobile.tsx +++ b/examples/react/e-commerce/components/ClearFiltersMobile.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useClearRefinements } from 'react-instantsearch-hooks-web'; +import { useClearRefinements } from 'react-instantsearch'; export function ClearFiltersMobile({ containerRef, diff --git a/examples/react-hooks/e-commerce/components/NoResults.tsx b/examples/react/e-commerce/components/NoResults.tsx similarity index 98% rename from examples/react-hooks/e-commerce/components/NoResults.tsx rename to examples/react/e-commerce/components/NoResults.tsx index d8bc4fcdb3..d925812e79 100644 --- a/examples/react-hooks/e-commerce/components/NoResults.tsx +++ b/examples/react/e-commerce/components/NoResults.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; import { ClearFilters } from './ClearFilters'; diff --git a/examples/react-hooks/e-commerce/components/NoResultsBoundary.tsx b/examples/react/e-commerce/components/NoResultsBoundary.tsx similarity index 88% rename from examples/react-hooks/e-commerce/components/NoResultsBoundary.tsx rename to examples/react/e-commerce/components/NoResultsBoundary.tsx index 0cc0db451c..5ca22f2c4b 100644 --- a/examples/react-hooks/e-commerce/components/NoResultsBoundary.tsx +++ b/examples/react/e-commerce/components/NoResultsBoundary.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; export function NoResultsBoundary({ children, diff --git a/examples/react-hooks/e-commerce/components/Pagination.css b/examples/react/e-commerce/components/Pagination.css similarity index 100% rename from examples/react-hooks/e-commerce/components/Pagination.css rename to examples/react/e-commerce/components/Pagination.css diff --git a/examples/react-hooks/e-commerce/components/Panel.tsx b/examples/react/e-commerce/components/Panel.tsx similarity index 100% rename from examples/react-hooks/e-commerce/components/Panel.tsx rename to examples/react/e-commerce/components/Panel.tsx diff --git a/examples/react-hooks/e-commerce/components/PriceSlider.css b/examples/react/e-commerce/components/PriceSlider.css similarity index 100% rename from examples/react-hooks/e-commerce/components/PriceSlider.css rename to examples/react/e-commerce/components/PriceSlider.css diff --git a/examples/react-hooks/e-commerce/components/PriceSlider.tsx b/examples/react/e-commerce/components/PriceSlider.tsx similarity index 98% rename from examples/react-hooks/e-commerce/components/PriceSlider.tsx rename to examples/react/e-commerce/components/PriceSlider.tsx index 2e2dac558f..470c54f66d 100644 --- a/examples/react-hooks/e-commerce/components/PriceSlider.tsx +++ b/examples/react/e-commerce/components/PriceSlider.tsx @@ -11,7 +11,7 @@ import { Ticks, GetHandleProps, } from 'react-compound-slider'; -import { useRange } from 'react-instantsearch-hooks-web'; +import { useRange } from 'react-instantsearch'; import './PriceSlider.css'; import { formatNumber } from '../utils'; diff --git a/examples/react-hooks/e-commerce/components/Ratings.tsx b/examples/react/e-commerce/components/Ratings.tsx similarity index 97% rename from examples/react-hooks/e-commerce/components/Ratings.tsx rename to examples/react/e-commerce/components/Ratings.tsx index c07a3bc32b..515e1f3ed9 100644 --- a/examples/react-hooks/e-commerce/components/Ratings.tsx +++ b/examples/react/e-commerce/components/Ratings.tsx @@ -5,7 +5,7 @@ import { RatingMenuWidgetDescription, } from 'instantsearch.js/es/connectors/rating-menu/connectRatingMenu'; import React from 'react'; -import { useConnector } from 'react-instantsearch-hooks-web'; +import { useConnector } from 'react-instantsearch'; export function Ratings({ attribute }: { attribute: string }) { const { refine, items, createURL } = useConnector< diff --git a/examples/react-hooks/e-commerce/components/ResultsNumberMobile.tsx b/examples/react/e-commerce/components/ResultsNumberMobile.tsx similarity index 80% rename from examples/react-hooks/e-commerce/components/ResultsNumberMobile.tsx rename to examples/react/e-commerce/components/ResultsNumberMobile.tsx index ecd21d0b9d..f6e54f5363 100644 --- a/examples/react-hooks/e-commerce/components/ResultsNumberMobile.tsx +++ b/examples/react/e-commerce/components/ResultsNumberMobile.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; import { formatNumber } from '../utils'; diff --git a/examples/react-hooks/e-commerce/components/SaveFiltersMobile.tsx b/examples/react/e-commerce/components/SaveFiltersMobile.tsx similarity index 83% rename from examples/react-hooks/e-commerce/components/SaveFiltersMobile.tsx rename to examples/react/e-commerce/components/SaveFiltersMobile.tsx index d543f8b8b0..69b565bc96 100644 --- a/examples/react-hooks/e-commerce/components/SaveFiltersMobile.tsx +++ b/examples/react/e-commerce/components/SaveFiltersMobile.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; import { formatNumber } from '../utils'; diff --git a/examples/react-hooks/e-commerce/components/ScrollTo.tsx b/examples/react/e-commerce/components/ScrollTo.tsx similarity index 93% rename from examples/react-hooks/e-commerce/components/ScrollTo.tsx rename to examples/react/e-commerce/components/ScrollTo.tsx index ed2a7e8f82..b715b6010e 100644 --- a/examples/react-hooks/e-commerce/components/ScrollTo.tsx +++ b/examples/react/e-commerce/components/ScrollTo.tsx @@ -1,6 +1,6 @@ import { Middleware } from 'instantsearch.js'; import React, { useEffect, useRef } from 'react'; -import { useInstantSearch } from 'react-instantsearch-hooks-web'; +import { useInstantSearch } from 'react-instantsearch'; export function ScrollTo({ children }: { children: React.ReactNode }) { const { addMiddlewares } = useInstantSearch(); diff --git a/examples/react-hooks/e-commerce/components/index.ts b/examples/react/e-commerce/components/index.ts similarity index 100% rename from examples/react-hooks/e-commerce/components/index.ts rename to examples/react/e-commerce/components/index.ts diff --git a/examples/react-hooks/e-commerce/cx.ts b/examples/react/e-commerce/cx.ts similarity index 100% rename from examples/react-hooks/e-commerce/cx.ts rename to examples/react/e-commerce/cx.ts diff --git a/examples/react-hooks/e-commerce/env.js b/examples/react/e-commerce/env.js similarity index 100% rename from examples/react-hooks/e-commerce/env.js rename to examples/react/e-commerce/env.js diff --git a/examples/react/e-commerce/index.html b/examples/react/e-commerce/index.html index 6efaf5f290..4596053af8 100644 --- a/examples/react/e-commerce/index.html +++ b/examples/react/e-commerce/index.html @@ -8,9 +8,12 @@ /> - + + + + - E-commerce demo | Algolia + + React InstantSearch - e-commerce - +
+ + + diff --git a/examples/react/e-commerce/index.js b/examples/react/e-commerce/index.js deleted file mode 100644 index ae31e41347..0000000000 --- a/examples/react/e-commerce/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react-hooks/e-commerce/index.tsx b/examples/react/e-commerce/index.tsx similarity index 100% rename from examples/react-hooks/e-commerce/index.tsx rename to examples/react/e-commerce/index.tsx diff --git a/examples/react/e-commerce/package.json b/examples/react/e-commerce/package.json index 274bec4721..d16ab55775 100644 --- a/examples/react/e-commerce/package.json +++ b/examples/react/e-commerce/package.json @@ -1,14 +1,26 @@ { "name": "example-react-instantsearch-e-commerce", - "version": "15.0.0", + "version": "6.38.26", "private": true, + "scripts": { + "build": "BABEL_ENV=parcel parcel build index.html", + "website:examples": "BABEL_ENV=parcel parcel build index.html --public-url . --dist-dir=../../../website/examples/react/e-commerce", + "start": "BABEL_ENV=parcel parcel index.html" + }, + "browserslist": "firefox 68, chrome 78, IE 11", "dependencies": { "algoliasearch": "4.14.3", - "classnames": "2.2.6", - "qs": "6.9.7", - "react": "17.0.2", - "react-compound-slider": "2.2.0", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" + "instantsearch.js": "4.56.8", + "react": "18.1.0", + "react-compound-slider": "3.4.0", + "react-dom": "18.1.0", + "react-instantsearch": "6.47.3" + }, + "devDependencies": { + "@parcel/core": "2.8.0", + "@parcel/packager-raw-url": "2.8.0", + "@parcel/transformer-webmanifest": "2.8.0", + "parcel": "2.8.0", + "typescript": "5.1.3" } } diff --git a/examples/react-hooks/e-commerce/routing.ts b/examples/react/e-commerce/routing.ts similarity index 100% rename from examples/react-hooks/e-commerce/routing.ts rename to examples/react/e-commerce/routing.ts diff --git a/examples/react/e-commerce/utils.js b/examples/react/e-commerce/utils.js deleted file mode 100644 index fd3146d6af..0000000000 --- a/examples/react/e-commerce/utils.js +++ /dev/null @@ -1,3 +0,0 @@ -export function formatNumber(value) { - return Number(value).toLocaleString(); -} diff --git a/examples/react-hooks/e-commerce/utils/index.ts b/examples/react/e-commerce/utils/index.ts similarity index 100% rename from examples/react-hooks/e-commerce/utils/index.ts rename to examples/react/e-commerce/utils/index.ts diff --git a/examples/react/e-commerce/widgets/ClearFiltersMobile.js b/examples/react/e-commerce/widgets/ClearFiltersMobile.js deleted file mode 100644 index 8efb972c4d..0000000000 --- a/examples/react/e-commerce/widgets/ClearFiltersMobile.js +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { connectCurrentRefinements } from 'react-instantsearch-dom'; - -const ClearFiltersMobile = ({ items, refine, containerRef }) => { - function onClick() { - refine(items); - document.body.classList.remove('filtering'); - containerRef.current.scrollIntoView(); - } - - return ( -
- -
- ); -}; - -export default connectCurrentRefinements(ClearFiltersMobile); diff --git a/examples/react/e-commerce/widgets/NoResults.js b/examples/react/e-commerce/widgets/NoResults.js deleted file mode 100644 index 2ca721dc2f..0000000000 --- a/examples/react/e-commerce/widgets/NoResults.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; -import { connectStateResults, ClearRefinements } from 'react-instantsearch-dom'; - -const NoResults = ({ searchResults }) => { - if (!searchResults || searchResults.nbHits > 0) { - return null; - } - - const hasRefinements = searchResults.getRefinements().length > 0; - const description = hasRefinements - ? 'Try to reset your applied filters.' - : 'Please try another query.'; - - return ( -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- Sorry, we can't find any matches to your query! -

-

{description}

- - - - - - - - - Clear filters -
- ), - }} - /> -
- ); -}; - -export default connectStateResults(NoResults); diff --git a/examples/react/e-commerce/widgets/Pagination.css b/examples/react/e-commerce/widgets/Pagination.css deleted file mode 100644 index d8cb995f42..0000000000 --- a/examples/react/e-commerce/widgets/Pagination.css +++ /dev/null @@ -1,3 +0,0 @@ -.ais-Pagination--noRefinement { - display: none; -} diff --git a/examples/react/e-commerce/widgets/PriceSlider.css b/examples/react/e-commerce/widgets/PriceSlider.css deleted file mode 100644 index 3491c587a1..0000000000 --- a/examples/react/e-commerce/widgets/PriceSlider.css +++ /dev/null @@ -1,49 +0,0 @@ -.ais-RangeSlider .slider-rail { - background-color: rgba(65, 66, 71, 0.08); - border-radius: 3px; - cursor: pointer; - height: 3px; - position: absolute; - width: 100%; -} - -.ais-RangeSlider .slider-track { - background-color: #e2a400; - border-radius: 3px; - cursor: pointer; - height: 3px; - position: absolute; -} - -.ais-RangeSlider .slider-tick { - cursor: grab; - display: flex; - font-size: 0.75rem; - font-weight: bold; - position: absolute; - text-align: center; - top: -28px; - transform: translateX(-50%); - user-select: none; -} - -.ais-RangeSlider .slider-handle { - background-image: linear-gradient(to top, #f5f5fa, #fff); - border-radius: 50%; - box-shadow: 0 4px 11px 0 rgba(37, 44, 97, 0.15), - 0 2px 3px 0 rgba(93, 100, 148, 0.2); - cursor: grab; - height: 16px; - outline: none; - position: absolute; - transform: translate(-50%, -50%); - width: 16px; - z-index: 1; -} - -@media (max-width: 899px) { - .ais-RangeSlider .slider-handle { - height: 1.5rem; - width: 1.5rem; - } -} diff --git a/examples/react/e-commerce/widgets/PriceSlider.js b/examples/react/e-commerce/widgets/PriceSlider.js deleted file mode 100644 index 4bc03937a0..0000000000 --- a/examples/react/e-commerce/widgets/PriceSlider.js +++ /dev/null @@ -1,143 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { Slider, Rail, Handles, Tracks, Ticks } from 'react-compound-slider'; -import { connectRange } from 'react-instantsearch-dom'; - -import { formatNumber } from '../utils'; -import './PriceSlider.css'; - -function Handle({ - domain: [min, max], - handle: { id, value, percent }, - disabled, - getHandleProps, -}) { - return ( - <> - {/* Dummy element to make the tooltip draggable */} -
-
- - ); -} - -const PriceSlider = ({ min, max, refine, currentRefinement, canRefine }) => { - const [ticksValues, setTicksValues] = useState([ - currentRefinement.min, - currentRefinement.max, - ]); - - useEffect(() => { - setTicksValues([currentRefinement.min, currentRefinement.max]); - }, [currentRefinement]); - - const onChange = (values) => { - refine({ min: values[0], max: values[1] }); - }; - - if ( - !canRefine || - ticksValues[0] === undefined || - ticksValues[1] === undefined - ) { - return null; - } - - return ( - - - {({ getRailProps }) => ( -
- )} - - - - {({ tracks, getTrackProps }) => ( -
- {tracks.map(({ id, source, target }) => ( -
- ))} -
- )} - - - - {({ handles, getHandleProps }) => ( -
- {handles.map((handle) => ( - - ))} -
- )} -
- - - {({ ticks }) => ( -
- {ticks.map(({ id, count, value, percent }) => ( -
- $ - {formatNumber(value)} -
- ))} -
- )} -
- - ); -}; - -export default connectRange(PriceSlider); diff --git a/examples/react/e-commerce/widgets/Ratings.js b/examples/react/e-commerce/widgets/Ratings.js deleted file mode 100644 index e0c400b1e6..0000000000 --- a/examples/react/e-commerce/widgets/Ratings.js +++ /dev/null @@ -1,84 +0,0 @@ -import cx from 'classnames'; -import React from 'react'; -import { connectRange } from 'react-instantsearch-dom'; - -const Ratings = ({ currentRefinement, refine, createURL, count }) => { - const ratings = new Array(4).fill(null).map((_, ratingIndex) => { - const value = 4 - ratingIndex; - - const itemsCount = count - .filter((countObj) => value <= parseInt(countObj.value, 10)) - .map((countObj) => countObj.count) - .reduce((sum, currentCount) => sum + currentCount, 0); - - return { - value, - count: itemsCount, - }; - }); - const stars = new Array(5).fill(null); - - return ( -
- -
- ); -}; - -export default connectRange(Ratings); diff --git a/examples/react/e-commerce/widgets/ResultsNumberMobile.js b/examples/react/e-commerce/widgets/ResultsNumberMobile.js deleted file mode 100644 index 25ee84949e..0000000000 --- a/examples/react/e-commerce/widgets/ResultsNumberMobile.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { connectStats } from 'react-instantsearch-dom'; - -import { formatNumber } from '../utils'; - -const ResultsNumberMobile = ({ nbHits }) => ( -
- {formatNumber(nbHits)} results -
-); - -export default connectStats(ResultsNumberMobile); diff --git a/examples/react/e-commerce/widgets/SaveFiltersMobile.js b/examples/react/e-commerce/widgets/SaveFiltersMobile.js deleted file mode 100644 index c241b57dd6..0000000000 --- a/examples/react/e-commerce/widgets/SaveFiltersMobile.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import { connectStats } from 'react-instantsearch-dom'; - -import { formatNumber } from '../utils'; - -const SaveFiltersMobile = ({ nbHits, onClick }) => ( - -); - -export default connectStats(SaveFiltersMobile); diff --git a/examples/react/e-commerce/widgets/index.js b/examples/react/e-commerce/widgets/index.js deleted file mode 100644 index 0503c3fa26..0000000000 --- a/examples/react/e-commerce/widgets/index.js +++ /dev/null @@ -1,6 +0,0 @@ -export { default as ClearFiltersMobile } from './ClearFiltersMobile'; -export { default as NoResults } from './NoResults'; -export { default as Ratings } from './Ratings'; -export { default as ResultsNumberMobile } from './ResultsNumberMobile'; -export { default as PriceSlider } from './PriceSlider'; -export { default as SaveFiltersMobile } from './SaveFiltersMobile'; diff --git a/examples/react/geo-search/README.md b/examples/react/geo-search/README.md deleted file mode 100644 index 230df74127..0000000000 --- a/examples/react/geo-search/README.md +++ /dev/null @@ -1,18 +0,0 @@ -This example shows how to perform a geo search using `react-instantsearch`. - -[![Edit geo-search](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/geo-search) - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/geo-search -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn start -``` - -Read more about `react-instantsearch` [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react/geo-search/index.html b/examples/react/geo-search/index.html deleted file mode 100644 index 9069dae4d2..0000000000 --- a/examples/react/geo-search/index.html +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - GeoSearch with React InstantSearch - - - -
- - - - diff --git a/examples/react/geo-search/package.json b/examples/react/geo-search/package.json deleted file mode 100644 index cbd4009bb2..0000000000 --- a/examples/react/geo-search/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "example-react-instantsearch-geo-search", - "version": "17.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "BABEL_ENV=parcel parcel index.html --port 3000", - "build": "BABEL_ENV=parcel parcel build index.html --public-url .", - "test": "jest --ci" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "react-test-renderer": "17.0.2" - }, - "jest": { - "transform": { - "^.+\\.(jsx?|tsx?)$": [ - "babel-jest", - { - "rootMode": "upward" - } - ] - } - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.css": "8.0.0", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4", - "react-instantsearch-dom-maps": "6.40.4" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/examples/react/geo-search/src/App.js b/examples/react/geo-search/src/App.js deleted file mode 100644 index 5c93bdbc3f..0000000000 --- a/examples/react/geo-search/src/App.js +++ /dev/null @@ -1,100 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import qs from 'qs'; -import React, { Component, Fragment } from 'react'; -import { InstantSearch, SearchBox, Configure } from 'react-instantsearch-dom'; -import { - GoogleMapsLoader, - GeoSearch, - Control, - Marker, -} from 'react-instantsearch-dom-maps'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76', - { - _useRequestCache: true, - } -); - -const updateAfter = 700; -const searchStateToUrl = (searchState) => - searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : ''; - -class App extends Component { - constructor() { - super(); - - this.state = { - searchState: qs.parse(window.location.search.slice(1)), - }; - - window.addEventListener('popstate', ({ state: searchState }) => { - this.setState({ searchState }); - }); - } - - onSearchStateChange = (searchState) => { - // update the URL when there is a new search state. - clearTimeout(this.debouncedSetState); - this.debouncedSetState = setTimeout(() => { - window.history.pushState( - searchState, - null, - searchStateToUrl(searchState) - ); - }, updateAfter); - - this.setState((previousState) => { - const hasQueryChanged = - previousState.searchState.query !== searchState.query; - - return { - ...previousState, - searchState: { - ...searchState, - boundingBox: !hasQueryChanged ? searchState.boundingBox : null, - }, - }; - }); - }; - - render() { - const { searchState } = this.state; - - const parameters = {}; - if (!searchState.boundingBox) { - parameters.aroundLatLngViaIP = true; - parameters.aroundRadius = 'all'; - } - - return ( - - - Type a destination or move the map to see the closest apartment. - - - {(google) => ( - - {({ hits }) => ( - - - {hits.map((hit) => ( - - ))} - - )} - - )} - - - ); - } -} - -export default App; diff --git a/examples/react/geo-search/src/__tests__/App.test.js b/examples/react/geo-search/src/__tests__/App.test.js deleted file mode 100644 index a22e5e0bd8..0000000000 --- a/examples/react/geo-search/src/__tests__/App.test.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from '../App'; - -describe('geo-search recipe', () => { - it('App renders without crashing', () => { - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react/geo-search/src/__tests__/__snapshots__/App.test.js.snap b/examples/react/geo-search/src/__tests__/__snapshots__/App.test.js.snap deleted file mode 100644 index b0eb2790b3..0000000000 --- a/examples/react/geo-search/src/__tests__/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`geo-search recipe App renders without crashing 1`] = ` -Array [ - "Type a destination or move the map to see the closest apartment.", -
-
- - - -
-
, -] -`; diff --git a/examples/react/geo-search/src/index.js b/examples/react/geo-search/src/index.js deleted file mode 100644 index c8325007bd..0000000000 --- a/examples/react/geo-search/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; -import 'instantsearch.css/themes/algolia.css'; -import './style.css'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react/geo-search/src/style.css b/examples/react/geo-search/src/style.css deleted file mode 100644 index 8cbc039f85..0000000000 --- a/examples/react/geo-search/src/style.css +++ /dev/null @@ -1,24 +0,0 @@ -body { - font-family: Roboto; - font-size: 16px; - color: #565a5c; -} - -.ais-InstantSearch__root { - display: flex; - flex-direction: column; -} - -.ais-SearchBox { - margin: 10px 0; -} - -.ais-GeoSearch { - padding-right: 0; - padding-left: 0; - height: 700px; -} - -.marker { - transform: translate(-50%, -100%) scale(0.5, 0.5); -} diff --git a/examples/react/getting-started/.editorconfig b/examples/react/getting-started/.editorconfig index 9d08a1a828..dd7255e8a4 100644 --- a/examples/react/getting-started/.editorconfig +++ b/examples/react/getting-started/.editorconfig @@ -1,7 +1,6 @@ root = true [*] -charset = utf-8 indent_style = space indent_size = 2 end_of_line = lf diff --git a/examples/react/getting-started/.gitignore b/examples/react/getting-started/.gitignore index d30f40ef44..bf78c5a78c 100644 --- a/examples/react/getting-started/.gitignore +++ b/examples/react/getting-started/.gitignore @@ -1,21 +1,23 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. - -# dependencies -/node_modules - -# testing -/coverage - -# production -/build - -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - +# Logs +logs +*.log npm-debug.log* yarn-debug.log* yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +.parcel-cache +*.local + +# Editor directories and files +.vscode +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/react/getting-started/index.html b/examples/react/getting-started/index.html index 733975c4be..0308154383 100644 --- a/examples/react/getting-started/index.html +++ b/examples/react/getting-started/index.html @@ -6,14 +6,13 @@ name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> - + -->
- + + diff --git a/examples/react/getting-started/package.json b/examples/react/getting-started/package.json index a16b0793b9..44742fd758 100644 --- a/examples/react/getting-started/package.json +++ b/examples/react/getting-started/package.json @@ -1,22 +1,23 @@ { "name": "example-react-instantsearch-getting-started", - "version": "1.0.7", + "version": "6.38.26", "private": true, "scripts": { - "start": "BABEL_ENV=parcel parcel index.html --port 3000", - "build": "BABEL_ENV=parcel parcel build index.html --public-url ." + "build": "BABEL_ENV=parcel parcel build index.html", + "start": "BABEL_ENV=parcel parcel index.html --port 3000" }, "dependencies": { "algoliasearch": "4.14.3", + "instantsearch.js": "4.56.8", "react": "18.1.0", "react-dom": "18.1.0", - "react-instantsearch-dom": "6.40.4" + "react-instantsearch": "6.47.3" }, "devDependencies": { - "@babel/core": "7.15.5", "@parcel/core": "2.8.0", "@parcel/packager-raw-url": "2.8.0", "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0" + "parcel": "2.8.0", + "typescript": "5.1.3" } } diff --git a/examples/react/getting-started/src/App.css b/examples/react/getting-started/src/App.css index 925ccd85ca..e01152732c 100644 --- a/examples/react/getting-started/src/App.css +++ b/examples/react/getting-started/src/App.css @@ -1,3 +1,14 @@ +body, +h1 { + margin: 0; + padding: 0; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; +} + em { background: cyan; font-style: normal; diff --git a/examples/react/getting-started/src/App.js b/examples/react/getting-started/src/App.js deleted file mode 100644 index 47ec80bae5..0000000000 --- a/examples/react/getting-started/src/App.js +++ /dev/null @@ -1,78 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import React from 'react'; -import { - InstantSearch, - Configure, - Hits, - SearchBox, - Panel, - RefinementList, - Pagination, - Highlight, -} from 'react-instantsearch-dom'; -import './App.css'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -function App() { - return ( -
-
-

- Getting started -

-

- using{' '} - - React InstantSearch - -

-
- -
- - -
-
- - - -
- -
- - - -
- -
-
-
-
-
-
- ); -} - -function Hit(props) { - return ( -
-

- -

-

- -

-
- ); -} - -export default App; diff --git a/examples/react-hooks/getting-started/src/App.tsx b/examples/react/getting-started/src/App.tsx similarity index 93% rename from examples/react-hooks/getting-started/src/App.tsx rename to examples/react/getting-started/src/App.tsx index e3c46105af..0945e92432 100644 --- a/examples/react-hooks/getting-started/src/App.tsx +++ b/examples/react/getting-started/src/App.tsx @@ -9,7 +9,7 @@ import { Pagination, RefinementList, SearchBox, -} from 'react-instantsearch-hooks-web'; +} from 'react-instantsearch'; import { Panel } from './Panel'; @@ -29,8 +29,8 @@ export function App() {

using{' '} - - React InstantSearch Hooks + + React InstantSearch

diff --git a/examples/react-hooks/getting-started/src/Panel.tsx b/examples/react/getting-started/src/Panel.tsx similarity index 100% rename from examples/react-hooks/getting-started/src/Panel.tsx rename to examples/react/getting-started/src/Panel.tsx diff --git a/examples/react-hooks/getting-started/src/env.js b/examples/react/getting-started/src/env.js similarity index 100% rename from examples/react-hooks/getting-started/src/env.js rename to examples/react/getting-started/src/env.js diff --git a/examples/react/getting-started/src/index.css b/examples/react/getting-started/src/index.css deleted file mode 100644 index 12f1b9911a..0000000000 --- a/examples/react/getting-started/src/index.css +++ /dev/null @@ -1,10 +0,0 @@ -body, -h1 { - margin: 0; - padding: 0; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, - Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; -} diff --git a/examples/react/getting-started/src/index.js b/examples/react/getting-started/src/index.js deleted file mode 100644 index 6f7ec3e532..0000000000 --- a/examples/react/getting-started/src/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; -import { createRoot } from 'react-dom/client'; - -import './index.css'; -import App from './App'; - -createRoot(document.getElementById('root')).render(); diff --git a/examples/react-hooks/getting-started/src/index.tsx b/examples/react/getting-started/src/index.tsx similarity index 100% rename from examples/react-hooks/getting-started/src/index.tsx rename to examples/react/getting-started/src/index.tsx diff --git a/examples/react/media/App.css b/examples/react/media/App.css deleted file mode 100644 index 1ab20f8543..0000000000 --- a/examples/react/media/App.css +++ /dev/null @@ -1,311 +0,0 @@ -html, -body { - margin: 0; - padding: 0; - font-size: 14px; -} - -body { - min-height: 100%; - font-family: Roboto; - background: #f1f1f1; -} - -a { - color: #333333; -} - -article hr { - margin: 10px 14px; - float: none; - width: initial; -} - -.is-logo { - float: left; - margin-left: 18px; -} - -.logo { - margin-left: 15px; - font-size: 30px; - font-weight: bold; - float: left; -} - -.logo:hover { - text-decoration: none; -} - -.logo i { - margin-left: 5px; - color: #e91d00; -} - -header { - background: #ffffff; - padding: 10px; - border-bottom: 1px solid #e8e8e8; - position: relative; - left: 0; - right: 0; - z-index: 2; -} - -.searchbox-container { - margin-left: 240px; - max-width: 400px; -} - -.searchbox-container .input-group { - margin-top: 5px; -} - -.searchbox-container .form-control:focus { - outline: none; - box-shadow: none; -} - -.searchbox-container button { - padding-left: 20px; - padding-right: 20px; - background: #f8f8f8; - border-radius: 0; -} - -section { - background: #f1f1f1; - min-height: 100%; - z-index: 1; -} - -section aside { - position: absolute; - top: 67px; - left: 0; - bottom: 0; - width: 230px; - background: #ffffff; - border-right: 1px solid #e8e8e8; -} - -.nav { - margin: 0 20px; -} - -.nav li a { - display: block; - padding: 2px 10px; - margin: 10px 0; -} - -.nav li a:hover { - color: #ffffff; - background: #333333; -} - -.nav li.separator { - height: 1px; - background: #e8e8e8; -} - -section aside h5 { - color: #ce1312; - margin-left: 30px; - text-transform: uppercase; - font-size: 10px; - margin-top: 20px; -} - -section aside .badge { - font-size: 0.8em; - background: #bbbbbb; - position: relative; - top: 1px; -} - -#genres .item { - display: block; - cursor: pointer; - padding: 4px 4px 4px 8px; - font-weight: normal; - font-size: 0.9em; - margin: 0 0 -1px; -} - -#genres .item:hover { - background: #333333; - color: #ffffff; - text-decoration: none; -} - -#genres .active .item { - border: 1px solid #ce1312; - margin-top: -1px; -} - -#genres .active .badge { - background: #333333; -} - -section article { - margin-top: 7px; - margin-bottom: 10px; - margin-left: 237px; - margin-right: 10px; - padding: 10px 0; - max-width: 100%; - background: #ffffff; - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); -} - -.ais-Stats-text { - padding-right: 14px; - font-size: 0.8em; - line-height: 24px; -} - -#hits { - padding: 0 15px; -} - -.ais-Pagination { - box-shadow: none; - border: none; - border-radius: initial; - padding: 0px; -} - -.ais-Pagination-item { - display: inline-block; - padding: 0px; -} - -.ais-Pagination-item + .ais-Pagination-item { - margin-left: 4px; -} - -.ais-Pagination-item--disabled { - display: none; -} - -.ais-Pagination-link { - display: block; - background: #f8f8f8; - padding: 3px 8px; - color: #333333; -} - -.ais-Pagination-item--selected .ais-Pagination-link { - border-color: #b5b5b5; - background: #e8e8e8; -} - -.ais-Pagination-link:hover { - text-decoration: none; - border-color: #cfcfcf; - background: #ebebeb; - color: #333333; -} - -.ais-Hits-list { - margin: 0; -} - -.ais-Hits-item { - margin: 0; - padding: 0; - border: none; - box-shadow: none; - width: 100%; -} - -.hit { - margin-bottom: 10px; - height: 130px; - border: 1px solid #f3f3f3; -} - -.hit em { - font-style: normal; - background: #ffffd4; - text-decoration: underline; -} - -.hit .media-object { - height: 130px; - width: 130px; - overflow: hidden; - background-size: contain; - background-repeat: no-repeat; - background-position: center center; -} - -.hit .media-heading { - color: #167ac6; - font-weight: normal; - font-size: 18px; -} - -.hit .media-body { - padding: 10px; -} - -.thank-you { - font-size: 0.8em; - margin-top: 18px; - margin-left: 30px; -} - -.thank-you a { - color: #ce1312; -} - -.stars { - margin-left: 5px; -} - -.star { - /* item star */ - display: inline-block; - width: 1em; - height: 1em; -} - -.star:before { - content: '\2605'; - color: #fbae00; -} - -.star__empty { - /* empty star */ - display: inline-block; - width: 1em; - height: 1em; -} - -.star__empty:before { - content: '\2606'; - color: #fbae00; -} - -.genre, -.year { - margin: 12px 0; -} - -.genre .badge + .badge { - margin-left: 4px; -} - -.year { - font-weight: bold; -} - -.genre .badge { - background: #bbbbbb; -} - -.ais-RatingMenu { - margin: 0 24px 0 28px; -} diff --git a/examples/react/media/App.js b/examples/react/media/App.js deleted file mode 100644 index 9f478f78ba..0000000000 --- a/examples/react/media/App.js +++ /dev/null @@ -1,198 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import React from 'react'; -import * as ReactInstantSearch from 'react-instantsearch-dom'; - -import withURLSync from './URLSync'; -import './App.css'; - -// Due to a bug in Webpack, we destructure here instead of using named imports -const { - InstantSearch, - Hits, - Stats, - Pagination, - RatingMenu, - Highlight, - Configure, - connectSearchBox, - connectRefinementList, -} = ReactInstantSearch; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = (props) => ( - - -
-
- - -
- -); - -const Header = () => ( -
- - React InstantSearch - - - You - - - -
-); - -const SearchBox = connectSearchBox(({ currentRefinement, refine }) => ( -
-
- refine(e.target.value)} - autoComplete="off" - className="form-control" - /> - - - -
-
-)); - -const Facets = () => ( - -); - -const Panel = ({ title, children, id }) => ( -
-
- {title} -
- {children} -
-); - -const Star = ({ active }) => ( - -); -const Stars = ({ rating }) => { - const stars = []; - for (let i = 1; i <= 5; ++i) { - stars.push(i <= rating); - } - return ( - - {stars.map((active, idx) => ( - - ))} - - ); -}; -const Genre = ({ name }) => {name}; -const Genres = ({ genres }) => ( -

- {genres.map((genre, idx) => ( - - ))} -

-); - -const Hit = (hit) => { - const { image, rating, year, genre } = hit.hit; - return ( -
-
-
-
-
-

- - -

-

{year}

- -
-
- ); -}; - -const Results = connectSearchBox(() => ( -
-
- -
-
-
- -
- -
-)); - -const RefinementListLinks = connectRefinementList( - ({ items, refine, createURL }) => { - const hitComponents = items.map((item) => ( - - )); - - return
{hitComponents}
; - } -); - -export default withURLSync(App); diff --git a/examples/react/media/URLSync.js b/examples/react/media/URLSync.js deleted file mode 100644 index 1eaa103822..0000000000 --- a/examples/react/media/URLSync.js +++ /dev/null @@ -1,56 +0,0 @@ -import qs from 'qs'; -import React, { Component } from 'react'; - -const updateAfter = 700; -const searchStateToURL = (searchState) => - searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : ''; - -const withURLSync = (App) => - class WithURLSync extends Component { - state = { - searchState: qs.parse(window.location.search.slice(1)), - }; - - componentDidMount() { - window.addEventListener('popstate', this.onPopState); - } - - componentWillUnmount() { - clearTimeout(this.debouncedSetState); - window.removeEventListener('popstate', this.onPopState); - } - - onPopState = ({ state }) => - this.setState({ - searchState: state || {}, - }); - - onSearchStateChange = (searchState) => { - clearTimeout(this.debouncedSetState); - - this.debouncedSetState = setTimeout(() => { - window.history.pushState( - searchState, - null, - searchStateToURL(searchState) - ); - }, updateAfter); - - this.setState({ searchState }); - }; - - render() { - const { searchState } = this.state; - - return ( - - ); - } - }; - -export default withURLSync; diff --git a/examples/react/media/index.html b/examples/react/media/index.html deleted file mode 100644 index fa5e8ca306..0000000000 --- a/examples/react/media/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - React InstantSearch - Media - - - - - -
- - diff --git a/examples/react/media/index.js b/examples/react/media/index.js deleted file mode 100644 index ae31e41347..0000000000 --- a/examples/react/media/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react/media/package.json b/examples/react/media/package.json deleted file mode 100644 index 6d6f235459..0000000000 --- a/examples/react/media/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "example-react-instantsearch-media", - "version": "15.0.0", - "private": true, - "dependencies": { - "algoliasearch": "4.14.3", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" - } -} diff --git a/examples/react/multi-index/README.md b/examples/react/multi-index/README.md deleted file mode 100644 index 36fdda4a8d..0000000000 --- a/examples/react/multi-index/README.md +++ /dev/null @@ -1,18 +0,0 @@ -This example shows how to target multiple indices using `react-instantsearch`. - -[![Edit multi-index](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/multi-index) - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/multi-index -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn start -``` - -Read more about `react-instantsearch` [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react/multi-index/index.html b/examples/react/multi-index/index.html deleted file mode 100644 index b6358d3fe4..0000000000 --- a/examples/react/multi-index/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - multi-index search with react-instantsearch - - -
- - - - diff --git a/examples/react/multi-index/package.json b/examples/react/multi-index/package.json deleted file mode 100644 index ab96e1c0a9..0000000000 --- a/examples/react/multi-index/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "example-react-instantsearch-multi-index", - "version": "17.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "BABEL_ENV=parcel parcel index.html --port 3000", - "build": "BABEL_ENV=parcel parcel build index.html --public-url .", - "test": "jest --ci" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "parcel": "2.8.0", - "react-test-renderer": "17.0.2" - }, - "jest": { - "transform": { - "^.+\\.(jsx?|tsx?)$": [ - "babel-jest", - { - "rootMode": "upward" - } - ] - } - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.css": "8.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/examples/react/multi-index/src/App.js b/examples/react/multi-index/src/App.js deleted file mode 100644 index d2c96a4434..0000000000 --- a/examples/react/multi-index/src/App.js +++ /dev/null @@ -1,22 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import React from 'react'; -import { InstantSearch, Hits, SearchBox, Index } from 'react-instantsearch-dom'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = () => ( - - -

Results in first dataset

- - -

Results in second dataset

- -
-
-); - -export default App; diff --git a/examples/react/multi-index/src/__tests__/App.test.js b/examples/react/multi-index/src/__tests__/App.test.js deleted file mode 100644 index 87bbba40a4..0000000000 --- a/examples/react/multi-index/src/__tests__/App.test.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from '../App'; - -describe('Multi index recipe', () => { - it('App renders without crashing', () => { - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react/multi-index/src/__tests__/__snapshots__/App.test.js.snap b/examples/react/multi-index/src/__tests__/__snapshots__/App.test.js.snap deleted file mode 100644 index df13ed610e..0000000000 --- a/examples/react/multi-index/src/__tests__/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,90 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Multi index recipe App renders without crashing 1`] = ` -Array [ -
-
- - - -
-
, -

- Results in first dataset -

, -
-
    -
, -

- Results in second dataset -

, -
-
    -
, -] -`; diff --git a/examples/react/multi-index/src/index.js b/examples/react/multi-index/src/index.js deleted file mode 100644 index 158b4bb248..0000000000 --- a/examples/react/multi-index/src/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; -import 'instantsearch.css/themes/algolia.css'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react-hooks/next-routing/.eslintrc b/examples/react/next-routing/.eslintrc similarity index 100% rename from examples/react-hooks/next-routing/.eslintrc rename to examples/react/next-routing/.eslintrc diff --git a/examples/react-hooks/next-routing/.gitignore b/examples/react/next-routing/.gitignore similarity index 100% rename from examples/react-hooks/next-routing/.gitignore rename to examples/react/next-routing/.gitignore diff --git a/examples/react/next-routing/README.md b/examples/react/next-routing/README.md new file mode 100644 index 0000000000..a909692883 --- /dev/null +++ b/examples/react/next-routing/README.md @@ -0,0 +1,18 @@ +This example shows how to do server side rendering with next.js and React InstantSearch. There's a live example here: https://codesandbox.io/s/github/algolia/instantsearch.js/tree/master/examples/react/next. + +[![Edit next-routing](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/next-routing) + +## Clone the example + +```sh +curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/next-routing +``` + +## Start the example + +```sh +yarn install --no-lockfile +yarn run dev +``` + +Read more about React InstantSearch [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react-hooks/next-routing/components/Panel.tsx b/examples/react/next-routing/components/Panel.tsx similarity index 100% rename from examples/react-hooks/next-routing/components/Panel.tsx rename to examples/react/next-routing/components/Panel.tsx diff --git a/examples/react-hooks/next-routing/next-env.d.ts b/examples/react/next-routing/next-env.d.ts similarity index 100% rename from examples/react-hooks/next-routing/next-env.d.ts rename to examples/react/next-routing/next-env.d.ts diff --git a/examples/react-hooks/next-routing/next.config.js b/examples/react/next-routing/next.config.js similarity index 100% rename from examples/react-hooks/next-routing/next.config.js rename to examples/react/next-routing/next.config.js diff --git a/examples/react-hooks/next/package.json b/examples/react/next-routing/package.json similarity index 70% rename from examples/react-hooks/next/package.json rename to examples/react/next-routing/package.json index c722e5cea1..166d14efa7 100644 --- a/examples/react-hooks/next/package.json +++ b/examples/react/next-routing/package.json @@ -1,5 +1,5 @@ { - "name": "example-react-instantsearch-hooks-next-example", + "name": "example-react-instantsearch-next-routing-example", "version": "6.57.0", "private": true, "scripts": { @@ -14,9 +14,8 @@ "next": "12.1.6", "react": "18.1.0", "react-dom": "18.1.0", - "react-instantsearch-hooks-router-nextjs": "6.47.3", - "react-instantsearch-hooks-server": "6.47.3", - "react-instantsearch-hooks-web": "6.47.3" + "react-instantsearch-router-nextjs": "6.47.3", + "react-instantsearch": "6.47.3" }, "devDependencies": { "@types/node": "17.0.40", diff --git a/examples/react-hooks/next-routing/pages/_app.js b/examples/react/next-routing/pages/_app.js similarity index 100% rename from examples/react-hooks/next-routing/pages/_app.js rename to examples/react/next-routing/pages/_app.js diff --git a/examples/react-hooks/next-routing/pages/index.tsx b/examples/react/next-routing/pages/index.tsx similarity index 93% rename from examples/react-hooks/next-routing/pages/index.tsx rename to examples/react/next-routing/pages/index.tsx index 9f636446ad..ee50bc2a2e 100644 --- a/examples/react-hooks/next-routing/pages/index.tsx +++ b/examples/react/next-routing/pages/index.tsx @@ -6,8 +6,6 @@ import Link from 'next/link'; import singletonRouter from 'next/router'; import React from 'react'; import { renderToString } from 'react-dom/server'; -import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs'; -import { getServerState } from 'react-instantsearch-hooks-server'; import { DynamicWidgets, InstantSearch, @@ -17,7 +15,9 @@ import { SearchBox, InstantSearchServerState, InstantSearchSSRProvider, -} from 'react-instantsearch-hooks-web'; + getServerState, +} from 'react-instantsearch'; +import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs'; import { Panel } from '../components/Panel'; @@ -52,7 +52,7 @@ export default function HomePage({ serverState, url }: HomePageProps) { return ( - React InstantSearch Hooks - Next.js + React InstantSearch - Next.js {/* If you have navigation links outside of InstantSearch */} diff --git a/examples/react-hooks/next-routing/pages/other-page.tsx b/examples/react/next-routing/pages/other-page.tsx similarity index 100% rename from examples/react-hooks/next-routing/pages/other-page.tsx rename to examples/react/next-routing/pages/other-page.tsx diff --git a/examples/react-hooks/next-routing/styles/globals.css b/examples/react/next-routing/styles/globals.css similarity index 100% rename from examples/react-hooks/next-routing/styles/globals.css rename to examples/react/next-routing/styles/globals.css diff --git a/examples/react-hooks/next-routing/tsconfig.json b/examples/react/next-routing/tsconfig.json similarity index 100% rename from examples/react-hooks/next-routing/tsconfig.json rename to examples/react/next-routing/tsconfig.json diff --git a/examples/react-hooks/next-routing/utils/cx.ts b/examples/react/next-routing/utils/cx.ts similarity index 100% rename from examples/react-hooks/next-routing/utils/cx.ts rename to examples/react/next-routing/utils/cx.ts diff --git a/examples/react-hooks/next/.eslintrc b/examples/react/next/.eslintrc similarity index 100% rename from examples/react-hooks/next/.eslintrc rename to examples/react/next/.eslintrc diff --git a/examples/react/next/.gitignore b/examples/react/next/.gitignore index e2ff68289a..1437c53f70 100644 --- a/examples/react/next/.gitignore +++ b/examples/react/next/.gitignore @@ -1,19 +1,34 @@ -# See https://help.github.com/ignore-files/ for more about ignoring files. +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies -node_modules +/node_modules +/.pnp +.pnp.js # testing /coverage +# next.js +/.next/ +/out/ + # production /build -/dist -/.next # misc .DS_Store -.env +*.pem + +# debug npm-debug.log* yarn-debug.log* yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/examples/react/next/README.md b/examples/react/next/README.md index 9b13b63924..f6a99da12c 100644 --- a/examples/react/next/README.md +++ b/examples/react/next/README.md @@ -15,4 +15,4 @@ yarn install --no-lockfile yarn run dev ``` -Read more about `react-instantsearch` [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). +Read more about React InstantSearch [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react-hooks/next/components/Panel.tsx b/examples/react/next/components/Panel.tsx similarity index 100% rename from examples/react-hooks/next/components/Panel.tsx rename to examples/react/next/components/Panel.tsx diff --git a/examples/react/next/components/app.js b/examples/react/next/components/app.js deleted file mode 100644 index 6e710e2f8c..0000000000 --- a/examples/react/next/components/app.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react'; -import { - RefinementList, - SearchBox, - Hits, - Configure, - Highlight, - Pagination, - InstantSearch, -} from 'react-instantsearch-dom'; - -const HitComponent = ({ hit }) => ( -
-
-
- -
-
-
-
- - - ${hit.price} - - {hit.rating} stars -
-
- -
-
- -
-
-
-); - -export function App(props) { - return ( - - -
-

React InstantSearch + Next.js

- -
-
-
- -
-
- -
-
- -
- ); -} diff --git a/examples/react/next/components/head.js b/examples/react/next/components/head.js deleted file mode 100644 index 509381a8bf..0000000000 --- a/examples/react/next/components/head.js +++ /dev/null @@ -1,35 +0,0 @@ -import NextHead from 'next/head'; -import React from 'react'; - -const defaultDescription = ''; -const defaultOGURL = ''; -const defaultOGImage = ''; - -export const Head = (props) => ( - - - {props.title || ''} - - - - - - - - - - - - - - -); diff --git a/examples/react/next/components/index.js b/examples/react/next/components/index.js deleted file mode 100644 index 6d94af2e30..0000000000 --- a/examples/react/next/components/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './head'; -export * from './app'; diff --git a/examples/react-hooks/next/next-env.d.ts b/examples/react/next/next-env.d.ts similarity index 100% rename from examples/react-hooks/next/next-env.d.ts rename to examples/react/next/next-env.d.ts diff --git a/examples/react/next/package.json b/examples/react/next/package.json index 251a0a7625..4956a848a9 100644 --- a/examples/react/next/package.json +++ b/examples/react/next/package.json @@ -1,31 +1,27 @@ { - "name": "example-react-instantsearch-next", - "version": "17.0.0", + "name": "example-react-instantsearch-next-example", + "version": "6.57.0", "private": true, - "license": "MIT", "scripts": { - "dev": "next", + "dev": "next dev", "build": "next build", - "start": "next start" - }, - "jest": { - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": [ - "babel-jest", - { - "presets": [ - "next/babel" - ] - } - ] - } + "start": "next start", + "lint": "next lint" }, "dependencies": { "algoliasearch": "4.14.3", - "next": "12.3.1", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" + "instantsearch.css": "8.0.0", + "next": "12.1.6", + "react": "18.1.0", + "react-dom": "18.1.0", + "react-instantsearch-router-nextjs": "6.47.3", + "react-instantsearch": "6.47.3" + }, + "devDependencies": { + "@types/node": "17.0.40", + "@types/react": "18.0.12", + "eslint": "8.4.0", + "eslint-config-next": "12.0.7", + "typescript": "5.1.3" } } diff --git a/examples/react-hooks/next/pages/_app.js b/examples/react/next/pages/_app.js similarity index 100% rename from examples/react-hooks/next/pages/_app.js rename to examples/react/next/pages/_app.js diff --git a/examples/react/next/pages/index.js b/examples/react/next/pages/index.js deleted file mode 100644 index d67d4dc83a..0000000000 --- a/examples/react/next/pages/index.js +++ /dev/null @@ -1,79 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import { useRouter } from 'next/router'; -import qs from 'qs'; -import React from 'react'; -import { findResultsState } from 'react-instantsearch-dom/server'; - -import { Head, App } from '../components'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const updateAfter = 700; - -const createURL = (state) => `?${qs.stringify(state)}`; - -const pathToSearchState = (path) => - path.includes('?') ? qs.parse(path.substring(path.indexOf('?') + 1)) : {}; - -const searchStateToURL = (searchState) => - searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : ''; - -const DEFAULT_PROPS = { - searchClient, - indexName: 'instant_search', -}; - -export default function Page(props) { - const [searchState, setSearchState] = React.useState(props.searchState); - const router = useRouter(); - const debouncedSetState = React.useRef(); - - React.useEffect(() => { - if (router) { - router.beforePopState(({ url }) => { - setSearchState(pathToSearchState(url)); - }); - } - }, [router]); - - return ( -
- - { - clearTimeout(debouncedSetState.current); - - debouncedSetState.current = setTimeout(() => { - const href = searchStateToURL(nextSearchState); - - router.push(href, href, { shallow: true }); - }, updateAfter); - - setSearchState(nextSearchState); - }} - createURL={createURL} - /> -
- ); -} - -export async function getServerSideProps({ resolvedUrl }) { - const searchState = pathToSearchState(resolvedUrl); - const resultsState = await findResultsState(App, { - ...DEFAULT_PROPS, - searchState, - }); - - return { - props: { - resultsState: JSON.parse(JSON.stringify(resultsState)), - searchState, - }, - }; -} diff --git a/examples/react-hooks/next/pages/index.tsx b/examples/react/next/pages/index.tsx similarity index 92% rename from examples/react-hooks/next/pages/index.tsx rename to examples/react/next/pages/index.tsx index 1930e8a670..f3f5340179 100644 --- a/examples/react-hooks/next/pages/index.tsx +++ b/examples/react/next/pages/index.tsx @@ -5,8 +5,6 @@ import Head from 'next/head'; import singletonRouter from 'next/router'; import React from 'react'; import { renderToString } from 'react-dom/server'; -import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs'; -import { getServerState } from 'react-instantsearch-hooks-server'; import { DynamicWidgets, InstantSearch, @@ -16,7 +14,9 @@ import { SearchBox, InstantSearchServerState, InstantSearchSSRProvider, -} from 'react-instantsearch-hooks-web'; + getServerState, +} from 'react-instantsearch'; +import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs'; import { Panel } from '../components/Panel'; @@ -47,7 +47,7 @@ export default function HomePage({ serverState, url }: HomePageProps) { return ( - React InstantSearch Hooks - Next.js + React InstantSearch - Next.js -
-

- React InstantSearch + Next.Js -

-
-
- - - -
-
-
-
-
-
-
-
-
-
    -
-
-
- -
-`; diff --git a/examples/react/next/tests/index.test.js b/examples/react/next/tests/index.test.js deleted file mode 100644 index 37518d463c..0000000000 --- a/examples/react/next/tests/index.test.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from '../pages/index'; - -describe('Next app recipes', () => { - it('App renders without crashing', () => { - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react-hooks/next/tsconfig.json b/examples/react/next/tsconfig.json similarity index 100% rename from examples/react-hooks/next/tsconfig.json rename to examples/react/next/tsconfig.json diff --git a/examples/react-hooks/next/utils/cx.ts b/examples/react/next/utils/cx.ts similarity index 100% rename from examples/react-hooks/next/utils/cx.ts rename to examples/react/next/utils/cx.ts diff --git a/examples/react/react-native-query-suggestions/.expo-shared/assets.json b/examples/react/react-native-query-suggestions/.expo-shared/assets.json deleted file mode 100644 index 1e6decfbb5..0000000000 --- a/examples/react/react-native-query-suggestions/.expo-shared/assets.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "12bb71342c6255bbf50437ec8f4441c083f47cdb74bd89160c15e4f43e52a1cb": true, - "40b842e832070c58deac6aa9e08fa459302ee3f9da492c7e77d93d2fbf4a56fd": true -} diff --git a/examples/react/react-native-query-suggestions/.gitignore b/examples/react/react-native-query-suggestions/.gitignore deleted file mode 100644 index c409cf6af4..0000000000 --- a/examples/react/react-native-query-suggestions/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -node_modules/**/* -.expo/* -npm-debug.* -*.jks -*.p8 -*.p12 -*.key -*.mobileprovision -*.orig.* -web-build/ -web-report/ - -# macOS -.DS_Store diff --git a/examples/react/react-native-query-suggestions/App.js b/examples/react/react-native-query-suggestions/App.js deleted file mode 100644 index c36f5f59ff..0000000000 --- a/examples/react/react-native-query-suggestions/App.js +++ /dev/null @@ -1,382 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { - InstantSearch, - Configure, - Index, - connectSearchBox, - connectInfiniteHits, - connectHits, - connectRefinementList, -} from 'react-instantsearch-native'; -import { - StyleSheet, - Text, - View, - TextInput, - FlatList, - Image, - Keyboard, - TouchableHighlight, -} from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; - -import Highlight from './Highlight'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const styles = StyleSheet.create({ - container: { - marginTop: 30, - flex: 1, - }, - suggestionsContainer: { - flex: 1, - }, - algoliaLogo: { - width: 40, - height: 40, - margin: 10, - }, - searchBoxContainer: { - flexDirection: 'row', - alignItems: 'stretch', - }, - bestResults: { - backgroundColor: 'lightgrey', - height: 40, - justifyContent: 'center', - padding: 10, - }, - searchBox: { - color: 'black', - height: 50, - width: 300, - alignSelf: 'center', - }, - hitsContainer: { - flexDirection: 'row', - margin: 10, - }, - suggestions: { - flexDirection: 'row', - alignItems: 'center', - padding: 10, - }, - suggestionsIcon: { - marginRight: 10, - }, - hitsPicture: { width: 40, height: 40 }, - hitsText: { - alignSelf: 'center', - paddingLeft: 5, - flex: 1, - flexWrap: 'wrap', - }, - hitsSeparator: { - height: 1, - backgroundColor: 'lightgrey', - marginTop: 10, - marginBottom: 10, - }, - categoryTextContainer: { - flexDirection: 'row', - alignItems: 'center', - }, - categoryTextIn: { fontStyle: 'italic' }, - categoryText: { color: '#cc8008' }, -}); - -export default class App extends React.Component { - constructor(props) { - super(props); - this.state = { - displaySuggestions: false, - isFirstKeystroke: true, - searchState: {}, - query: '', - category: null, - }; - this.displaySuggestions = this.displaySuggestions.bind(this); - this.removeSuggestions = this.removeSuggestions.bind(this); - this.setQuery = this.setQuery.bind(this); - this.onSearchStateChange = this.onSearchStateChange.bind(this); - this.firstKeystroke = this.firstKeystroke.bind(this); - this.clearFilter = this.clearFilter.bind(this); - } - - firstKeystroke() { - this.setState({ isFirstKeystroke: false }); - } - - displaySuggestions() { - this.setState({ displaySuggestions: true }); - } - - removeSuggestions() { - this.setState({ displaySuggestions: false, isFirstKeystroke: true }); - } - - setQuery(query, category) { - const { - query: _query, - page: _page, - ...searchState - } = this.state.searchState; - if (searchState.indices && searchState.indices.instant_search) { - searchState.indices.instant_search.page = 0; - } - this.setState({ - query, - searchState, - category, - displaySuggestions: false, - }); - } - - clearFilter() { - this.setState({ - category: null, - query: '', - }); - } - - onSearchStateChange(searchState) { - this.setState({ searchState }); - } - - render() { - const suggestions = this.state.displaySuggestions ? ( - - ) : null; - - const results = this.state.displaySuggestions ? ( - - ) : ( - - ); - return ( - - - - - - {suggestions} - - - - - - Best results - {this.state.category ? ` in ${this.state.category}` : null} - - {results} - - - - ); - } -} - -class SearchBox extends Component { - render() { - return ( - - - { - if (text === '') { - this.props.clearFilter(); - } - this.props.refine(text); - }} - value={this.props.currentRefinement} - placeholder={'Search a product...'} - placeholderTextColor={'black'} - clearButtonMode={'always'} - underlineColorAndroid={'white'} - spellCheck={false} - autoCorrect={false} - autoCapitalize={'none'} - onFocus={this.props.displaySuggestions} - onChange={() => { - if (this.props.isFirstKeystroke) { - this.props.displaySuggestions(); - this.props.firstKeystroke(); - } - }} - /> - - ); - } -} - -const ConnectedSearchBox = connectSearchBox(SearchBox); - -SearchBox.propTypes = { - currentRefinement: PropTypes.string, - displaySuggestions: PropTypes.func, - firstKeystroke: PropTypes.func, - refine: PropTypes.func, - isFirstKeystroke: PropTypes.bool, - clearFilter: PropTypes.func, -}; - -const HitsList = ({ hits, removeSuggestions, onEndReached }) => ( - ( - - - - - - - )} - data={hits} - keyExtractor={(item, index) => item.objectID + index} - onEndReached={onEndReached} - onScroll={() => { - Keyboard.dismiss(); - removeSuggestions(); - }} - ItemSeparatorComponent={() => } - /> -); - -HitsList.propTypes = { - hits: PropTypes.array, - removeSuggestions: PropTypes.func, - onEndReached: PropTypes.func, -}; - -const ResultsInfiniteHits = connectInfiniteHits( - ({ hits, hasMore, refine, removeSuggestions }) => ( - { - if (hasMore) { - refine(); - } - }} - /> - ) -); - -const ResultsHits = connectHits(({ hits, removeSuggestions }) => ( - -)); - -const SuggestionsHits = connectHits(({ hits, onPressItem }) => ( - { - const category = - index === 1 - ? item.instant_search.facets.exact_matches.categories[0].value - : null; - return ( - - ); - }} - keyExtractor={(item, index) => item.objectID + index} - data={hits.reduce((acc, hit, index) => { - if (index === 0) { - acc.push(hit); // we duplicate first hit to allow a refinement under or not category - } - acc.push(hit); - return acc; - }, [])} - keyboardShouldPersistTaps="always" - /> -)); - -const buildItemCategoryText = (categoryText) => ( - - in - {categoryText} - -); - -const Item = ({ item, category, onPressItem, index }) => { - let text = null; - if (index === 0) { - text = buildItemCategoryText('All our categories'); - } - if (category) { - text = buildItemCategoryText(category); - } - return ( - { - Keyboard.dismiss(); - onPressItem(item.query, category); - }} - underlayColor="white" - > - - - - {text} - - - ); -}; - -Item.propTypes = { - item: PropTypes.object, - index: PropTypes.number, - category: PropTypes.string, - onPressItem: PropTypes.func, -}; - -const VirtualRefinementList = connectRefinementList(() => null); diff --git a/examples/react/react-native-query-suggestions/App.test.js b/examples/react/react-native-query-suggestions/App.test.js deleted file mode 100644 index 911027b854..0000000000 --- a/examples/react/react-native-query-suggestions/App.test.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from './App'; - -it('renders without crashing', () => { - const rendered = renderer.create().toJSON(); - expect(rendered).toBeTruthy(); -}); diff --git a/examples/react/react-native-query-suggestions/Highlight.js b/examples/react/react-native-query-suggestions/Highlight.js deleted file mode 100644 index ed8abe2f66..0000000000 --- a/examples/react/react-native-query-suggestions/Highlight.js +++ /dev/null @@ -1,24 +0,0 @@ -import React from 'react'; -import { connectHighlight } from 'react-instantsearch-native'; -import { Text } from 'react-native'; - -export default connectHighlight( - ({ highlight, attribute, hit, highlightProperty, inverted }) => { - const parsedHit = highlight({ attribute, hit, highlightProperty }); - const styles = inverted ? {} : { backgroundColor: '#ffff99' }; - const highligtedHit = parsedHit.map((part, idx) => { - if (part.isHighlighted) - return ( - - {part.value} - - ); - return ( - - {part.value} - - ); - }); - return {highligtedHit}; - } -); diff --git a/examples/react/react-native-query-suggestions/app.json b/examples/react/react-native-query-suggestions/app.json deleted file mode 100644 index 43de963985..0000000000 --- a/examples/react/react-native-query-suggestions/app.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "expo": { - "name": "NewProject", - "slug": "NewProject", - "platforms": [ - "ios", - "android", - "web" - ], - "version": "1.0.0", - "orientation": "portrait", - "icon": "./assets/icon.png", - "splash": { - "image": "./assets/splash.png", - "resizeMode": "contain", - "backgroundColor": "#ffffff" - }, - "updates": { - "fallbackToCacheTimeout": 0 - }, - "assetBundlePatterns": [ - "**/*" - ], - "ios": { - "supportsTablet": true - } - } -} diff --git a/examples/react/react-native-query-suggestions/assets/icon.png b/examples/react/react-native-query-suggestions/assets/icon.png deleted file mode 100644 index 6eaf302953..0000000000 Binary files a/examples/react/react-native-query-suggestions/assets/icon.png and /dev/null differ diff --git a/examples/react/react-native-query-suggestions/assets/splash.png b/examples/react/react-native-query-suggestions/assets/splash.png deleted file mode 100644 index cc94f379de..0000000000 Binary files a/examples/react/react-native-query-suggestions/assets/splash.png and /dev/null differ diff --git a/examples/react/react-native-query-suggestions/babel.config.js b/examples/react/react-native-query-suggestions/babel.config.js deleted file mode 100644 index 9d89e13119..0000000000 --- a/examples/react/react-native-query-suggestions/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = function (api) { - api.cache(true); - return { - presets: ['babel-preset-expo'], - }; -}; diff --git a/examples/react/react-native-query-suggestions/package.json b/examples/react/react-native-query-suggestions/package.json deleted file mode 100644 index ab60f82b8c..0000000000 --- a/examples/react/react-native-query-suggestions/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "example-react-instantsearch-react-native-query-suggestions", - "version": "14.0.0", - "main": "node_modules/expo/AppEntry.js", - "scripts": { - "build": "echo \"Error: no build specified\" && exit 0", - "start": "expo start", - "android": "expo start --android", - "ios": "expo start --ios", - "web": "expo start --web", - "eject": "expo eject", - "test": "echo \"Error: no test specified\" && exit 0", - "test:actual": "jest" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "expo": "37.0.3", - "prop-types": "15.6.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-native": "6.40.4", - "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz", - "react-native-vector-icons": "6.6.0", - "react-native-web": "0.11.7" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "babel-preset-expo": "8.1.0", - "jest-expo": "37.0.0", - "react-test-renderer": "17.0.2" - }, - "private": true, - "jest": { - "preset": "jest-expo", - "transformIgnorePatterns": [ - "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)" - ] - } -} diff --git a/examples/react/react-native-query-suggestions/tests/App.test.js b/examples/react/react-native-query-suggestions/tests/App.test.js deleted file mode 100644 index a1a214221f..0000000000 --- a/examples/react/react-native-query-suggestions/tests/App.test.js +++ /dev/null @@ -1,14 +0,0 @@ -import 'react-native'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from '../App'; - -// Note: test renderer must be required after react-native. - -Date.now = jest.fn(() => 0); - -test('renders correctly', () => { - const tree = renderer.create().toJSON(); - expect(tree).toMatchSnapshot(); -}); diff --git a/examples/react/react-native-query-suggestions/tests/__snapshots__/App.test.js.snap b/examples/react/react-native-query-suggestions/tests/__snapshots__/App.test.js.snap deleted file mode 100644 index 2014155b3e..0000000000 --- a/examples/react/react-native-query-suggestions/tests/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,108 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` - - - - - - - Best results - - - - - - - -`; diff --git a/examples/react-hooks/react-native/.eslintignore b/examples/react/react-native/.eslintignore similarity index 100% rename from examples/react-hooks/react-native/.eslintignore rename to examples/react/react-native/.eslintignore diff --git a/examples/react-hooks/react-native/.eslintrc b/examples/react/react-native/.eslintrc similarity index 100% rename from examples/react-hooks/react-native/.eslintrc rename to examples/react/react-native/.eslintrc diff --git a/examples/react/react-native/.gitignore b/examples/react/react-native/.gitignore index c409cf6af4..ec8a36a257 100644 --- a/examples/react/react-native/.gitignore +++ b/examples/react/react-native/.gitignore @@ -1,5 +1,6 @@ -node_modules/**/* -.expo/* +node_modules/ +.expo/ +dist/ npm-debug.* *.jks *.p8 @@ -8,7 +9,6 @@ npm-debug.* *.mobileprovision *.orig.* web-build/ -web-report/ # macOS .DS_Store diff --git a/examples/react/react-native/App.js b/examples/react/react-native/App.js deleted file mode 100644 index 1834f618b9..0000000000 --- a/examples/react/react-native/App.js +++ /dev/null @@ -1,74 +0,0 @@ -import React, { Component } from 'react'; -import { Platform } from 'react-native'; -import { Router, Scene } from 'react-native-router-flux'; - -import Categories from './src/Categories'; -import Filters from './src/Filters'; -import Home from './src/Home'; -import Price from './src/Price'; -import Rating from './src/Rating'; -import Type from './src/Type'; - -export default class App extends Component { - render() { - return ( - - - - - - - - - - - ); - } -} diff --git a/examples/react-hooks/react-native/App.tsx b/examples/react/react-native/App.tsx similarity index 95% rename from examples/react-hooks/react-native/App.tsx rename to examples/react/react-native/App.tsx index 8f5f867a1a..d00d36a366 100644 --- a/examples/react-hooks/react-native/App.tsx +++ b/examples/react/react-native/App.tsx @@ -2,7 +2,7 @@ import React, { useRef } from 'react'; import { FlatList, SafeAreaView, StyleSheet, Text, View } from 'react-native'; import { StatusBar } from 'expo-status-bar'; import algoliasearch from 'algoliasearch/lite'; -import { InstantSearch } from 'react-instantsearch-hooks'; +import { InstantSearch } from 'react-instantsearch-core'; import { InfiniteHits } from './src/InfiniteHits'; import { SearchBox } from './src/SearchBox'; diff --git a/examples/react/react-router/README.md b/examples/react/react-native/README.md similarity index 54% rename from examples/react/react-router/README.md rename to examples/react/react-native/README.md index 44563a9650..84e51c5d31 100644 --- a/examples/react/react-router/README.md +++ b/examples/react/react-native/README.md @@ -1,18 +1,20 @@ -This example shows how to synchronize your instantsearch url if you are using react-router. +# React InstantSearch with React Native -[![Edit react-router](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/react-router) +[![Edit react-native](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/react-native) + +This example shows how to use React InstantSearch with React Native. ## Clone the example ```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/react-router +curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/react-native ``` ## Start the example ```sh yarn install --no-lockfile -yarn start +yarn run start ``` -Read more about react-instantsearch [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). +Read more about React InstantSearch [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). diff --git a/examples/react/react-native/app.json b/examples/react/react-native/app.json index 74151c399a..476db9aec0 100644 --- a/examples/react/react-native/app.json +++ b/examples/react/react-native/app.json @@ -1,12 +1,7 @@ { "expo": { - "name": "my-project", - "slug": "my-project", - "platforms": [ - "ios", - "android", - "web" - ], + "name": "ais-ecommerce-demo-app", + "slug": "ais-ecommerce-demo-app", "version": "1.0.0", "orientation": "portrait", "icon": "./assets/icon.png", @@ -18,11 +13,18 @@ "updates": { "fallbackToCacheTimeout": 0 }, - "assetBundlePatterns": [ - "**/*" - ], + "assetBundlePatterns": ["**/*"], "ios": { "supportsTablet": true + }, + "android": { + "adaptiveIcon": { + "foregroundImage": "./assets/adaptive-icon.png", + "backgroundColor": "#FFFFFF" + } + }, + "web": { + "favicon": "./assets/favicon.png" } } } diff --git a/examples/react-hooks/react-native/assets/adaptive-icon.png b/examples/react/react-native/assets/adaptive-icon.png similarity index 100% rename from examples/react-hooks/react-native/assets/adaptive-icon.png rename to examples/react/react-native/assets/adaptive-icon.png diff --git a/examples/react-hooks/react-native/assets/favicon.png b/examples/react/react-native/assets/favicon.png similarity index 100% rename from examples/react-hooks/react-native/assets/favicon.png rename to examples/react/react-native/assets/favicon.png diff --git a/examples/react/react-native/assets/icon.png b/examples/react/react-native/assets/icon.png index 6eaf302953..a0b1526fc7 100644 Binary files a/examples/react/react-native/assets/icon.png and b/examples/react/react-native/assets/icon.png differ diff --git a/examples/react/react-native/assets/splash.png b/examples/react/react-native/assets/splash.png index cc94f379de..0e89705a94 100644 Binary files a/examples/react/react-native/assets/splash.png and b/examples/react/react-native/assets/splash.png differ diff --git a/examples/react/react-native/package.json b/examples/react/react-native/package.json index 94e3bc7d09..147f50883c 100644 --- a/examples/react/react-native/package.json +++ b/examples/react/react-native/package.json @@ -1,46 +1,30 @@ { - "name": "example-react-instantsearch-react-native", - "version": "14.0.0", + "name": "example-react-instantsearch-react-native-example", + "version": "6.38.26", + "private": true, "main": "node_modules/expo/AppEntry.js", "scripts": { - "build": "echo \"Error: no build specified\" && exit 0", "start": "expo start", "android": "expo start --android", "ios": "expo start --ios", "web": "expo start --web", - "eject": "expo eject", - "test": "echo \"Error: no test specified\" && exit 0", - "test:actual": "jest" + "eject": "expo eject" }, "dependencies": { - "@ptomasroos/react-native-multi-slider": "2.2.2", "algoliasearch": "4.14.3", - "expo": "37.0.3", - "prop-types": "15.6.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-native": "6.40.4", - "react-native": "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz", - "react-native-gesture-handler": "1.6.1", - "react-native-modal-dropdown": "0.7.0", - "react-native-reanimated": "1.7.0", - "react-native-router-flux": "4.2.0", - "react-native-screens": "2.2.0", - "react-native-star-rating": "1.1.0", - "react-native-vector-icons": "6.6.0", - "react-native-web": "~0.11.7" + "expo": "~44.0.0", + "expo-status-bar": "~1.2.0", + "instantsearch.js": "4.56.8", + "react": "17.0.1", + "react-instantsearch-core": "6.47.3", + "react-native": "0.64.3", + "react-native-web": "0.17.1" }, "devDependencies": { "@babel/core": "7.15.5", - "babel-preset-expo": "8.1.0", - "jest-expo": "37.0.0", - "react-test-renderer": "17.0.2" - }, - "private": true, - "jest": { - "preset": "jest-expo", - "transformIgnorePatterns": [ - "node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*|deprecated-react-native-listview|@ptomasroos/react-native-multi-slider)" - ] + "@types/react": "~17.0.21", + "@types/react-native": "~0.64.12", + "expo-cli": "5.1.1", + "typescript": "5.1.3" } } diff --git a/examples/react/react-native/src/Categories.js b/examples/react/react-native/src/Categories.js deleted file mode 100644 index 0ae137555d..0000000000 --- a/examples/react/react-native/src/Categories.js +++ /dev/null @@ -1,216 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { - InstantSearch, - connectMenu, - connectRefinementList, - connectSearchBox, - connectRange, -} from 'react-instantsearch-native'; -import { - StyleSheet, - Text, - View, - FlatList, - TextInput, - Platform, - TouchableHighlight, - Keyboard, -} from 'react-native'; -import Icon from 'react-native-vector-icons/FontAwesome'; - -import Highlight from './components/Highlight'; -import Spinner from './components/Spinner'; -import Stats from './components/Stats'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const styles = StyleSheet.create({ - mainContainer: { - backgroundColor: 'white', - flex: 1, - }, - item: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - backgroundColor: 'white', - minHeight: 41, - padding: 11, - }, - itemRefined: { - fontWeight: 'bold', - }, - searchBoxContainer: { - backgroundColor: '#162331', - }, - searchBox: { - backgroundColor: 'white', - height: 40, - flex: 1, - borderWidth: 1, - padding: 10, - margin: 10, - ...Platform.select({ - ios: { - borderRadius: 5, - }, - android: {}, - }), - }, -}); - -class Filters extends Component { - static displayName = 'React Native example'; - - constructor(props) { - super(props); - this.onSearchStateChange = this.onSearchStateChange.bind(this); - this.state = { - searchState: props.searchState, - }; - } - - onSearchStateChange(nextState) { - const searchState = { ...this.state.searchState, ...nextState }; - this.setState({ searchState }); - this.props.onSearchStateChange(searchState); - } - - render() { - return ( - - - - - - - - - - - ); - } -} - -Filters.propTypes = { - searchState: PropTypes.object.isRequired, - onSearchStateChange: PropTypes.func.isRequired, -}; - -export default Filters; - -class Menu extends Component { - constructor(props) { - super(props); - this.saveQuery = this.saveQuery.bind(this); - this.state = { - query: '', - }; - } - - saveQuery(text) { - this.setState({ query: text }); - } - - render() { - const { items, searchForItems } = this.props; - const facets = this ? ( - - ) : null; - - return ( - - - - { - this.saveQuery(text); - searchForItems(text); - }} - placeholder={'Search a category...'} - value={this.state.query} - clearButtonMode={'always'} - underlineColorAndroid={'white'} - spellCheck={false} - autoCorrect={false} - autoCapitalize={'none'} - /> - - {facets} - - ); - } - - _renderRow = ({ item: refinement }) => { - const icon = refinement.isRefined ? ( - - ) : ( - - ); - - const label = this.props.isFromSearch ? ( - - ) : ( - refinement.label - ); - - return ( - { - this.saveQuery(''); - this.props.refine(refinement.value); - Keyboard.dismiss(); - }} - > - - - {label} - - {icon} - - - ); - }; - - _renderSeparator = (sectionID, rowID, adjacentRowHighlighted) => ( - - ); -} - -Menu.propTypes = { - query: PropTypes.string, - saveQuery: PropTypes.func, - searchForItems: PropTypes.func, - refine: PropTypes.func, - items: PropTypes.array, - isFromSearch: PropTypes.bool, -}; - -const ConnectedMenu = connectMenu(Menu); -const VirtualSearchBox = connectSearchBox(() => null); -const VirtualRefinementList = connectRefinementList(() => null); -const VirtualRange = connectRange(() => null); diff --git a/examples/react/react-native/src/Filters.js b/examples/react/react-native/src/Filters.js deleted file mode 100644 index c743ef5039..0000000000 --- a/examples/react/react-native/src/Filters.js +++ /dev/null @@ -1,193 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { - InstantSearch, - connectCurrentRefinements, - connectMenu, - connectRange, - connectRefinementList, - connectSearchBox, -} from 'react-instantsearch-native'; -import { - StyleSheet, - Text, - View, - FlatList, - TouchableHighlight, - Keyboard, -} from 'react-native'; -import { Actions } from 'react-native-router-flux'; -import Icon from 'react-native-vector-icons/FontAwesome'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const styles = StyleSheet.create({ - mainContainer: { - backgroundColor: 'white', - flexGrow: 1, - }, - filtersRow: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - padding: 10, - }, - clearAll: { - color: 'blue', - fontWeight: 'bold', - padding: 10, - alignSelf: 'center', - }, -}); - -class Filters extends Component { - static displayName = 'React Native example'; - constructor(props) { - super(props); - this.onSearchStateChange = this.onSearchStateChange.bind(this); - this.state = { - searchState: this.props.searchState, - }; - Keyboard.dismiss(); - } - onSearchStateChange(nextState) { - const searchState = { ...this.state.searchState, ...nextState }; - this.setState({ searchState }); - this.props.onSearchStateChange(searchState); - } - - render() { - return ( - - - - - - - - - - - ); - } -} - -Filters.propTypes = { - searchState: PropTypes.object, - onSearchStateChange: PropTypes.func.isRequired, -}; - -class Refinements extends React.Component { - constructor(props) { - super(props); - this._renderRow = this._renderRow.bind(this); - this.mapping = { - Categories: { - attribute: 'category', - value: (item) => item.currentRefinement, - }, - Type: { - attribute: 'type', - value: (item) => { - const values = item.items.map((i) => i.label).join(' - '); - return values; - }, - }, - Price: { - attribute: 'price', - value: (item) => - `From ${item.currentRefinement.min}$ to ${item.currentRefinement.max}$`, - }, - Rating: { - attribute: 'rating', - value: (item) => - `From ${item.currentRefinement.min} stars to ${item.currentRefinement.max} stars`, - }, - ClearRefinements: { - attribute: 'clearAll', - }, - }; - } - - _renderRow = ({ item: refinement }) => { - const item = this.props.items.find( - (i) => i.attribute === this.mapping[refinement].attribute - ); - const refinementValue = item ? this.mapping[refinement].value(item) : '-'; - const filtersRow = - refinement !== 'ClearRefinements' ? ( - { - Actions[refinement]({ - searchState: this.props.searchState, - onSearchStateChange: this.props.onSearchStateChange, - }); - }} - > - - - {refinement} - {refinementValue} - - - - - - - ) : ( - this.props.refine(this.props.items)}> - - CLEAR ALL - - - ); - return {filtersRow}; - }; - - _renderSeparator = (sectionID, rowId, adjacentRowHighlighted) => ( - - ); - render() { - return ( - - - - ); - } -} - -Refinements.propTypes = { - searchState: PropTypes.object.isRequired, - refine: PropTypes.func.isRequired, - onSearchStateChange: PropTypes.func.isRequired, - items: PropTypes.array.isRequired, -}; - -const ConnectedRefinements = connectCurrentRefinements(Refinements); -const VirtualRefinementList = connectRefinementList(() => null); -const VirtualSearchBox = connectSearchBox(() => null); -const VirtualMenu = connectMenu(() => null); -const VirtualRange = connectRange(() => null); - -export default Filters; diff --git a/examples/react-hooks/react-native/src/Highlight.tsx b/examples/react/react-native/src/Highlight.tsx similarity index 100% rename from examples/react-hooks/react-native/src/Highlight.tsx rename to examples/react/react-native/src/Highlight.tsx diff --git a/examples/react/react-native/src/Home.js b/examples/react/react-native/src/Home.js deleted file mode 100644 index 0f71f3bb01..0000000000 --- a/examples/react/react-native/src/Home.js +++ /dev/null @@ -1,351 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { - InstantSearch, - connectSearchBox, - connectInfiniteHits, - connectRefinementList, - connectStats, - connectMenu, - connectSortBy, - connectRange, - connectCurrentRefinements, -} from 'react-instantsearch-native'; -import { - StyleSheet, - Text, - View, - FlatList, - TextInput, - Image, - StatusBar, - Button, - Platform, - Dimensions, -} from 'react-native'; -import ModalDropdown from 'react-native-modal-dropdown'; -import { Actions } from 'react-native-router-flux'; -import RatingMenu from 'react-native-star-rating'; -import IosIcon from 'react-native-vector-icons/Ionicons'; -import MaterialIcon from 'react-native-vector-icons/MaterialIcons'; - -import Highlight from './components/Highlight'; -import Spinner from './components/Spinner'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const { height } = Dimensions.get('window'); - -const styles = StyleSheet.create({ - maincontainer: { - flex: 1, - }, - items: { - ...Platform.select({ - ios: { - height: height - 170, - }, - android: { height: height - 165 }, - }), - }, - item: { - flexDirection: 'row', - alignItems: 'center', - backgroundColor: 'white', - }, - options: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - backgroundColor: 'white', - padding: 5, - borderBottomColor: 'gray', - borderBottomWidth: 1, - }, - sortBy: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - paddingLeft: 8, - }, - searchBoxContainer: { - backgroundColor: '#162331', - flexDirection: 'row', - alignItems: 'center', - }, - searchBox: { - backgroundColor: 'white', - height: 40, - borderWidth: 1, - padding: 10, - margin: 10, - flexGrow: 1, - ...Platform.select({ - ios: { - borderRadius: 5, - }, - android: {}, - }), - }, - itemContent: { - paddingLeft: 15, - display: 'flex', - marginRight: 5, - }, - itemName: { - fontSize: 15, - fontWeight: 'bold', - paddingBottom: 5, - }, - itemType: { - fontSize: 13, - fontWeight: '200', - paddingBottom: 5, - }, - itemPrice: { - fontSize: 15, - fontWeight: 'bold', - paddingBottom: 5, - }, - starRating: { alignSelf: 'flex-start' }, - filters: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'space-between', - }, -}); -class Home extends Component { - static displayName = 'React Native example'; - constructor(props) { - super(props); - - this.state = { - searchState: this.props.searchState ? this.props.searchState : {}, - }; - } - - onSearchStateChange = (nextState) => { - this.setState({ searchState: { ...this.state.searchState, ...nextState } }); - }; - - render() { - return ( - - - - - - - - - - - - - - - - - - ); - } -} - -Home.propTypes = { - searchState: PropTypes.object, -}; - -export default Home; - -class SearchBox extends Component { - render() { - return ( - - - this.props.refine(text)} - value={this.props.currentRefinement} - placeholder={'Search a product...'} - clearButtonMode={'always'} - underlineColorAndroid={'white'} - spellCheck={false} - autoCorrect={false} - autoCapitalize={'none'} - /> - - ); - } -} - -SearchBox.propTypes = { - refine: PropTypes.func.isRequired, - currentRefinement: PropTypes.string, -}; - -const ConnectedSearchBox = connectSearchBox(SearchBox); - -class Hits extends Component { - onEndReached = () => { - if (this.props.hasMore) { - this.props.refine(); - } - }; - - render() { - const hits = - this.props.hits.length > 0 ? ( - - - - ) : null; - return hits; - } - - _renderRow = ({ item: hit }) => ( - - - - - - - - - - ${hit.price} - - - - - - ); - - _renderSeparator = (sectionID, rowID, adjacentRowHighlighted) => ( - - ); -} - -Hits.propTypes = { - hits: PropTypes.array.isRequired, - refine: PropTypes.func.isRequired, - hasMore: PropTypes.bool.isRequired, -}; - -const ConnectedHits = connectInfiniteHits(Hits); -const ConnectedStats = connectStats(({ nbHits }) => ( - {nbHits} products found -)); - -const ConnectedSortBy = connectSortBy( - ({ refine, items, currentRefinement }) => { - const icon = - Platform.OS === 'ios' ? ( - - ) : ( - - ); - return ( - - item.value === currentRefinement).label - } - onSelect={(index, value) => - refine(items.find((item) => item.label === value).value) - } - options={items.map((item) => item.label)} - renderRow={(item) => { - const itemValue = items.find((i) => i.label === item).value; - return ( - - {item} - - ); - }} - dropdownStyle={{ - width: 200, - height: 110, - }} - textStyle={{ fontSize: 15 }} - /> - {icon} - - ); - } -); - -const Filters = connectCurrentRefinements( - ({ items, searchState, onSearchStateChange }) => ( - - - -
-
- - Search by - - - - - - - -
-
-
-
-

- Hierarchical Menu -

-
-

- Menu -

- -`; diff --git a/examples/react/react-router-v3/src/index.js b/examples/react/react-router-v3/src/index.js deleted file mode 100644 index 30d3445317..0000000000 --- a/examples/react/react-router-v3/src/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Router, Route, browserHistory } from 'react-router'; - -import App from './App'; -import 'instantsearch.css/themes/algolia.css'; - -ReactDOM.render( - - - , - document.getElementById('root') -); diff --git a/examples/react/react-router/index.html b/examples/react/react-router/index.html deleted file mode 100644 index 2b8d16e55d..0000000000 --- a/examples/react/react-router/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - react-router feat react-instantsearch - - -
- - - - diff --git a/examples/react/react-router/package.json b/examples/react/react-router/package.json deleted file mode 100644 index 60f8911cb6..0000000000 --- a/examples/react/react-router/package.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "name": "example-react-instantsearch-react-router", - "version": "17.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "BABEL_ENV=parcel parcel index.html --port 3000", - "build": "BABEL_ENV=parcel parcel build index.html --public-url .", - "test": "jest --ci" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@parcel/core": "2.8.0", - "@parcel/packager-raw-url": "2.8.0", - "@parcel/transformer-webmanifest": "2.8.0", - "history": "4.10.1", - "parcel": "2.8.0", - "react-test-renderer": "17.0.2" - }, - "jest": { - "transform": { - "^.+\\.(jsx?|tsx?)$": [ - "babel-jest", - { - "rootMode": "upward" - } - ] - } - }, - "dependencies": { - "algoliasearch": "4.14.3", - "instantsearch.css": "8.0.0", - "prop-types": "15.6.2", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4", - "react-router-dom": "5.2.0" - }, - "browserslist": [ - ">0.2%", - "not dead", - "not ie <= 11", - "not op_mini all" - ] -} diff --git a/examples/react/react-router/src/App.js b/examples/react/react-router/src/App.js deleted file mode 100644 index 943f70f791..0000000000 --- a/examples/react/react-router/src/App.js +++ /dev/null @@ -1,120 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import qs from 'qs'; -import React from 'react'; -import { - InstantSearch, - HierarchicalMenu, - Hits, - Menu, - Pagination, - PoweredBy, - RatingMenu, - RefinementList, - SearchBox, - ClearRefinements, -} from 'react-instantsearch-dom'; -import { useLocation, useHistory } from 'react-router-dom'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const DEBOUNCE_TIME = 700; - -const createURL = (state) => `?${qs.stringify(state)}`; - -const searchStateToUrl = (location, searchState) => - searchState ? `${location.pathname}${createURL(searchState)}` : ''; - -const urlToSearchState = (location) => qs.parse(location.search.slice(1)); - -function App() { - const location = useLocation(); - const history = useHistory(); - const [searchState, setSearchState] = React.useState( - urlToSearchState(location) - ); - const setStateId = React.useRef(); - - React.useEffect(() => { - const nextSearchState = urlToSearchState(location); - - if (JSON.stringify(searchState) !== JSON.stringify(nextSearchState)) { - setSearchState(nextSearchState); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [location]); - - function onSearchStateChange(nextSearchState) { - clearTimeout(setStateId.current); - - setStateId.current = setTimeout(() => { - history.push( - searchStateToUrl(location, nextSearchState), - nextSearchState - ); - }, DEBOUNCE_TIME); - - setSearchState(nextSearchState); - } - - return ( - -
-
- - -
- -
-
-

Hierarchical Menu

- -

Menu

- -

Refinement List

- -

Range Ratings

- -
- -
-
- -
-
- -
-
- -
-
-
-
-
- ); -} - -export default App; diff --git a/examples/react/react-router/src/__tests__/App.test.js b/examples/react/react-router/src/__tests__/App.test.js deleted file mode 100644 index 48a0974423..0000000000 --- a/examples/react/react-router/src/__tests__/App.test.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { createMemoryHistory } from 'history'; -import React from 'react'; -import { Router, Route } from 'react-router-dom/cjs/react-router-dom.min'; -import renderer from 'react-test-renderer'; - -import App from '../App'; - -const history = createMemoryHistory('/'); - -describe('react-router recipe', () => { - it('App renders without crashing', () => { - const component = renderer.create( - - - - ); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react/react-router/src/__tests__/__snapshots__/App.test.js.snap b/examples/react/react-router/src/__tests__/__snapshots__/App.test.js.snap deleted file mode 100644 index f8c748c6ca..0000000000 --- a/examples/react/react-router/src/__tests__/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,749 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`react-router recipe App renders without crashing 1`] = ` -
-
-
-
- - - -
-
-
- - Search by - - - - - - - -
-
-
-
-

- Hierarchical Menu -

-
-

- Menu -

- -`; diff --git a/examples/react/react-router/src/index.js b/examples/react/react-router/src/index.js deleted file mode 100644 index a2e3434281..0000000000 --- a/examples/react/react-router/src/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { BrowserRouter as Router, Route } from 'react-router-dom'; - -import App from './App'; -import 'instantsearch.css/themes/algolia.css'; - -ReactDOM.render( - - - , - document.getElementById('root') -); diff --git a/examples/react/server-side-rendering/.babelrc b/examples/react/server-side-rendering/.babelrc deleted file mode 100644 index 5ac80001d4..0000000000 --- a/examples/react/server-side-rendering/.babelrc +++ /dev/null @@ -1,14 +0,0 @@ -{ - "presets": [ - [ - "@babel/preset-env", - { - "targets": { - "browsers": ["last 2 versions", "ie >= 9"] - } - } - ], - "@babel/preset-react" - ], - "plugins": ["@babel/plugin-proposal-class-properties"] -} diff --git a/examples/react/server-side-rendering/.gitignore b/examples/react/server-side-rendering/.gitignore deleted file mode 100644 index 6b5733e87b..0000000000 --- a/examples/react/server-side-rendering/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -node_modules -.DS_STORE -.idea -dist -npm-debug.log diff --git a/examples/react/server-side-rendering/README.md b/examples/react/server-side-rendering/README.md deleted file mode 100644 index 51c0b5338c..0000000000 --- a/examples/react/server-side-rendering/README.md +++ /dev/null @@ -1,20 +0,0 @@ -This example shows how to do server side rendering and React InstantSearch. - -[![Edit server-side-rendering](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/server-side-rendering) - -## Clone the example - -```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/server-side-rendering -``` - -## Start the example - -```sh -yarn install --no-lockfile -yarn start -``` - -Read more about react-instantsearch [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). - -This example was made possible thanks to https://github.com/Roilan/react-server-boilerplate. diff --git a/examples/react/server-side-rendering/package.json b/examples/react/server-side-rendering/package.json deleted file mode 100644 index 977d712098..0000000000 --- a/examples/react/server-side-rendering/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "example-react-instantsearch-server-side-rendering", - "version": "17.0.0", - "private": true, - "license": "MIT", - "scripts": { - "start": "webpack && nodemon dist/server.js", - "watch": "webpack --watch", - "build": "webpack --mode=production", - "test": "jest" - }, - "devDependencies": { - "@babel/core": "7.15.5", - "@babel/plugin-proposal-class-properties": "7.4.4", - "@babel/polyfill": "7.4.4", - "@babel/preset-env": "7.4.5", - "@babel/preset-react": "7.0.0", - "babel-core": "6.26.3", - "babel-jest": "27.4.6", - "babel-loader": "8.2.2", - "jest": "27.4.7", - "nodemon": "1.19.3", - "react-test-renderer": "17.0.2", - "webpack": "4.41.5", - "webpack-cli": "3.3.7", - "webpack-node-externals": "1.7.2" - }, - "dependencies": { - "algoliasearch": "4.14.3", - "express": "4.17.1", - "prop-types": "15.6.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4" - } -} diff --git a/examples/react/server-side-rendering/src/App.js b/examples/react/server-side-rendering/src/App.js deleted file mode 100644 index 30107b60f2..0000000000 --- a/examples/react/server-side-rendering/src/App.js +++ /dev/null @@ -1,53 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { - InstantSearch, - RefinementList, - SearchBox, - Hits, - Configure, - CurrentRefinements, -} from 'react-instantsearch-dom'; - -class App extends Component { - static propTypes = { - indexName: PropTypes.string.isRequired, - searchClient: PropTypes.object.isRequired, - searchState: PropTypes.object, - resultsState: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.object), - PropTypes.object, - ]), - }; - - static defaultProps = { - searchState: {}, - }; - - state = { - searchState: this.props.searchState, - }; - - onSearchStateChange = (nextSearchState) => - this.setState({ searchState: nextSearchState }); - - render() { - const { searchState } = this.state; - - return ( - - - - - - - - ); - } -} - -export default App; diff --git a/examples/react/server-side-rendering/src/App.test.js b/examples/react/server-side-rendering/src/App.test.js deleted file mode 100644 index e649516171..0000000000 --- a/examples/react/server-side-rendering/src/App.test.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import React from 'react'; -import renderer from 'react-test-renderer'; - -import App from './App'; - -describe('Server-side rendering recipes', () => { - it('App renders without crashing', () => { - const props = { - indexName: 'index', - searchClient: { - search() {}, - }, - }; - - const component = renderer.create(); - - expect(component.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/examples/react/server-side-rendering/src/__snapshots__/App.test.js.snap b/examples/react/server-side-rendering/src/__snapshots__/App.test.js.snap deleted file mode 100644 index eaee2542aa..0000000000 --- a/examples/react/server-side-rendering/src/__snapshots__/App.test.js.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Server-side rendering recipes App renders without crashing 1`] = ` -Array [ -
-
- - - -
-
, -
-
    -
, -
, -
-
    -
, -] -`; diff --git a/examples/react/server-side-rendering/src/browser.js b/examples/react/server-side-rendering/src/browser.js deleted file mode 100644 index ffe39ab140..0000000000 --- a/examples/react/server-side-rendering/src/browser.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import { hydrate } from 'react-dom'; - -import { createApp } from './createApp'; - -const { App, props } = createApp(); - -const __APP_INITIAL_STATE__ = window.__APP_INITIAL_STATE__; - -delete window.__APP_INITIAL_STATE__; - -hydrate( - , - document.getElementById('root') -); diff --git a/examples/react/server-side-rendering/src/createApp.js b/examples/react/server-side-rendering/src/createApp.js deleted file mode 100644 index 719b62e577..0000000000 --- a/examples/react/server-side-rendering/src/createApp.js +++ /dev/null @@ -1,23 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; - -import App from './App'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -export const createApp = () => { - const indexName = 'instant_search'; - const props = { - indexName, - searchClient, - }; - - return { - App, - props, - }; -}; - -export default App; diff --git a/examples/react/server-side-rendering/src/server.js b/examples/react/server-side-rendering/src/server.js deleted file mode 100644 index 136865f2a4..0000000000 --- a/examples/react/server-side-rendering/src/server.js +++ /dev/null @@ -1,50 +0,0 @@ -import { join } from 'path'; - -import express from 'express'; -import React from 'react'; -import { renderToString } from 'react-dom/server'; -import { findResultsState } from 'react-instantsearch-dom/server'; - -import { createApp } from './createApp'; -import template from './template'; - -const server = express(); - -server.use('/assets', express.static(join(__dirname, 'assets'))); - -server.get('/', async (_, res) => { - const { App, props } = createApp(); - - const searchState = { - query: 'iPhone', - page: 5, - refinementList: { - brand: ['Apple'], - }, - }; - - const resultsState = await findResultsState(App, { - ...props, - searchState, - }); - - const initialState = { - searchState, - resultsState, - }; - - const plainHTML = renderToString(); - - res.send( - template({ - body: plainHTML, - title: 'Hello World from the server', - initialState: JSON.stringify(initialState), - }) - ); -}); - -server.listen(8080, () => { - // eslint-disable-next-line no-console - console.log('Listening on: http://localhost:8080'); -}); diff --git a/examples/react/server-side-rendering/src/template.js b/examples/react/server-side-rendering/src/template.js deleted file mode 100644 index af8840c660..0000000000 --- a/examples/react/server-side-rendering/src/template.js +++ /dev/null @@ -1,16 +0,0 @@ -export default ({ body, title, initialState }) => - ` - - - - - ${title} - - - -
${body}
- - - - - `; diff --git a/examples/react/server-side-rendering/webpack.config.js b/examples/react/server-side-rendering/webpack.config.js deleted file mode 100644 index 8f62568efa..0000000000 --- a/examples/react/server-side-rendering/webpack.config.js +++ /dev/null @@ -1,64 +0,0 @@ -const path = require('path'); - -const nodeExternals = require('webpack-node-externals'); - -module.exports = [ - { - mode: 'development', - entry: ['@babel/polyfill', './src/server.js'], - output: { - path: path.join(__dirname, 'dist'), - filename: 'server.js', - libraryTarget: 'commonjs2', - publicPath: '/', - }, - target: 'node', - node: { - console: false, - global: false, - process: false, - Buffer: false, - __filename: false, - __dirname: false, - }, - externals: nodeExternals(), - module: { - rules: [ - { - test: /\.js$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - }, - ], - }, - ], - }, - }, - { - mode: 'development', - entry: ['@babel/polyfill', './src/browser.js'], - output: { - path: path.join(__dirname, 'dist/assets'), - publicPath: '/', - filename: 'bundle.js', - }, - module: { - rules: [ - { - test: /\.js$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - }, - ], - }, - ], - }, - resolve: { - extensions: ['.js', '.jsx'], - }, - }, -]; diff --git a/examples/react-hooks/ssr/.babelrc b/examples/react/ssr/.babelrc similarity index 100% rename from examples/react-hooks/ssr/.babelrc rename to examples/react/ssr/.babelrc diff --git a/examples/react-hooks/ssr/.eslintrc.js b/examples/react/ssr/.eslintrc.js similarity index 100% rename from examples/react-hooks/ssr/.eslintrc.js rename to examples/react/ssr/.eslintrc.js diff --git a/examples/react-hooks/ssr/.gitignore b/examples/react/ssr/.gitignore similarity index 100% rename from examples/react-hooks/ssr/.gitignore rename to examples/react/ssr/.gitignore diff --git a/examples/react-hooks/ssr/README.md b/examples/react/ssr/README.md similarity index 67% rename from examples/react-hooks/ssr/README.md rename to examples/react/ssr/README.md index 01e9e81973..2383220fce 100644 --- a/examples/react-hooks/ssr/README.md +++ b/examples/react/ssr/README.md @@ -1,13 +1,13 @@ -# React InstantSearch Hooks | Server-side rendering +# React InstantSearch | Server-side rendering -[![Edit ssr](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/ssr) +[![Edit ssr](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/ssr) -This example shows how to do server-side rendering with React InstantSearch Hooks. +This example shows how to do server-side rendering with React InstantSearch. ## Clone the example ```sh -curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react-hooks/ssr +curl https://codeload.github.com/algolia/instantsearch/tar.gz/master | tar -xz --strip=3 instantsearch-master/examples/react/ssr ``` ## Start the example diff --git a/examples/react-hooks/ssr/package.json b/examples/react/ssr/package.json similarity index 80% rename from examples/react-hooks/ssr/package.json rename to examples/react/ssr/package.json index 8b9bb9d61c..16447684b7 100644 --- a/examples/react-hooks/ssr/package.json +++ b/examples/react/ssr/package.json @@ -1,5 +1,5 @@ { - "name": "example-react-instantsearch-hooks-server-side-rendering", + "name": "example-react-instantsearch-server-side-rendering", "version": "6.38.26", "private": true, "license": "MIT", @@ -26,7 +26,6 @@ "express": "4.17.1", "react": "18.1.0", "react-dom": "18.1.0", - "react-instantsearch-hooks-server": "6.47.3", - "react-instantsearch-hooks-web": "6.47.3" + "react-instantsearch": "6.47.3" } } diff --git a/examples/react-hooks/ssr/src/App.js b/examples/react/ssr/src/App.js similarity index 98% rename from examples/react-hooks/ssr/src/App.js rename to examples/react/ssr/src/App.js index c561be4549..5d7e479095 100644 --- a/examples/react-hooks/ssr/src/App.js +++ b/examples/react/ssr/src/App.js @@ -11,7 +11,7 @@ import { Pagination, RefinementList, SearchBox, -} from 'react-instantsearch-hooks-web'; +} from 'react-instantsearch'; // because this is ran on node without type: "module" set in the package.json // we need to use commonjs instead of esm. // If you use ESM in Node, you can rely on these import statements instead: diff --git a/examples/react-hooks/ssr/src/browser.js b/examples/react/ssr/src/browser.js similarity index 100% rename from examples/react-hooks/ssr/src/browser.js rename to examples/react/ssr/src/browser.js diff --git a/examples/react-hooks/ssr/src/cx.js b/examples/react/ssr/src/cx.js similarity index 100% rename from examples/react-hooks/ssr/src/cx.js rename to examples/react/ssr/src/cx.js diff --git a/examples/react-hooks/ssr/src/searchClient.js b/examples/react/ssr/src/searchClient.js similarity index 100% rename from examples/react-hooks/ssr/src/searchClient.js rename to examples/react/ssr/src/searchClient.js diff --git a/examples/react-hooks/ssr/src/server.js b/examples/react/ssr/src/server.js similarity index 93% rename from examples/react-hooks/ssr/src/server.js rename to examples/react/ssr/src/server.js index b6ed8c6957..56a1804e5b 100644 --- a/examples/react-hooks/ssr/src/server.js +++ b/examples/react/ssr/src/server.js @@ -3,7 +3,7 @@ import { join } from 'path'; import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; -import { getServerState } from 'react-instantsearch-hooks-server'; +import { getServerState } from 'react-instantsearch'; import App from './App'; @@ -30,11 +30,11 @@ app.get('/', async (req, res) => { - +
${html}
- + ` ); diff --git a/examples/react-hooks/ssr/webpack.config.js b/examples/react/ssr/webpack.config.js similarity index 100% rename from examples/react-hooks/ssr/webpack.config.js rename to examples/react/ssr/webpack.config.js diff --git a/examples/react/tourism/App.css b/examples/react/tourism/App.css deleted file mode 100644 index 3b3bd6aa70..0000000000 --- a/examples/react/tourism/App.css +++ /dev/null @@ -1,448 +0,0 @@ -html, -body { - margin: 0; - padding: 0; -} - -body { - font-family: Roboto; - font-size: 16px; - color: #565a5c; -} - -.search-filters { - display: flex; -} - -.aisdemo--left-column { - height: 400px; - flex: 2 1 0; -} - -.aisdemo--right-column { - position: relative; - height: 400px; - flex: 1 1 0; -} - -/* HEADER -// ------------------------- */ -.aisdemo-navbar { - margin: 0; - border-bottom: 1px solid #dce0e0; - position: relative; - z-index: 99; -} - -.aisdemo-navbar .is-logo { - display: inline-block; - position: relative; - top: -8px; - left: 16px; -} - -.aisdemo-navbar .logo { - display: inline-block; - padding: 14px 22px; - font-size: 40px; - line-height: 1; - font-family: Courier; - color: #ff585b; - border-right: 1px solid #dce0e0; -} - -.aisdemo-navbar .fa-search { - font-size: 30px; - margin-left: 10px; - color: #dce0e0; -} - -.ais-SearchBox { - position: absolute; - width: 280px; - height: 33px; - white-space: nowrap; - box-sizing: border-box; - font-size: 14px; - left: 205px; - top: 20px; -} - -.ais-SearchBox-body, -.ais-SearchBox-form { - width: 100%; - height: 100%; -} - -.ais-SearchBox-input { - display: inline-block; - -webkit-transition: box-shadow 0.4s ease, background 0.4s ease; - transition: box-shadow 0.4s ease, background 0.4s ease; - border: 0; - border-radius: 1px; - box-shadow: inset 0 0 0 0px #cccccc; - background: #ffffff; - padding: 0; - width: 100%; - height: 100%; - vertical-align: middle; - white-space: normal; - font-size: inherit; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.ais-SearchBox-input::-webkit-search-decoration, -.ais-SearchBox-input::-webkit-search-cancel-button, -.ais-SearchBox-input::-webkit-search-results-button, -.ais-SearchBox-input::-webkit-search-results-decoration { - display: none; -} - -.ais-SearchBox-input:hover { - box-shadow: inset 0 0 0 0px #b3b3b3; -} - -.ais-SearchBox-input:focus, -.SearchBox__input:active { - outline: 0; - box-shadow: inset 0 0 0 0px #d6dee3; - background: #ffffff; -} - -.ais-SearchBox-input::-webkit-input-placeholder { - color: #9aaeb5; -} - -.ais-SearchBox-input::-moz-placeholder { - color: #9aaeb5; -} - -.ais-SearchBox-input:-ms-input-placeholder { - color: #9aaeb5; -} - -.ais-SearchBox-input::placeholder { - color: #9aaeb5; -} - -.ais-SearchBox-submit { - display: none; -} - -.ais-SearchBox-reset { - display: none; -} - -/* FILTERS -// ------------------------- */ -.aisdemo-filters .aisdemo-filter { - margin-top: 0; - margin-bottom: 0; - padding-top: 15px; - padding-bottom: 15px; - border-bottom: 1px solid #dce0e0; -} - -.aisdemo-filters .aisdemo-filter-title { - font-size: 1em; - font-weight: normal; - padding-top: 9px; - padding-left: 30px; -} - -.aisdemo-filters .date, -.aisdemo-filters #guests select { - font-size: 0.8em; - padding: 8px 10px; - border: 1px solid #dce0e0; -} - -.aisdemo-filters #guests select { - width: 100%; - padding-right: 20px; - border-radius: 0; - background: transparent; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.aisdemo-filters #guests select:focus { - outline: none; -} - -.aisdemo-filters .guests-caret:before { - line-height: 1; - position: absolute; - top: 0; - right: 20px; - width: 2em; - padding-top: 0.8em; - content: '\25bc'; - text-align: center; - pointer-events: none; - color: #82888a; -} - -.ais-refinement-list--count { - display: none; -} - -.ais-refinement-list--item { - display: inline-block; - cursor: pointer; -} - -.ais-refinement-list--item label { - font-size: 0.8em; - font-weight: normal; - box-sizing: border-box; - width: 100%; - padding: 9px 10px 7px; - background: #edefed; - border-radius: 4px; -} - -.ais-refinement-list--checkbox { - position: relative; - bottom: 3px; - float: right; - width: 1.25em; - height: 1.25em; - margin-left: 20px; - vertical-align: top; - border: 1px solid #dce0e0; - background: #ffffff; - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; -} - -.ais-refinement-list--checkbox:focus { - outline: none; -} - -.ais-refinement-list--item__active .ais-refinement-list--checkbox:before { - font-size: 0.85em; - position: absolute; - width: 1.25em; - content: '\2713'; - text-align: center; - color: #ff5a5f; -} - -.ais-GeoSearch-map { - height: 400px; -} - -.ClearGeoRefinement button { - display: block; - position: absolute; - left: 50%; - bottom: 20px; - transform: translateX(-50%); - background-color: #ff585b; - color: #fff; - padding: 5px; - border-radius: 3px; - font-size: 0.85em; -} - -.ClearGeoRefinement button:disabled { - display: none; -} - -/* STATS -// ------------------------- */ -#stats { - font-size: 1em; - font-weight: normal; - position: absolute; - bottom: 0; - padding: 5px 15px; -} - -/* MAP -// ------------------------- */ -#map { - height: 400px; -} - -.marker { - transform: translate(-50%, -100%) scale(0.5, 0.5); -} - -.capacity-filter { - padding: 9px 10px 7px; - background: #edefed; -} - -.capacity-menu-wrapper { - font-size: 0.8em; - font-weight: normal; - box-sizing: border-box; - width: 100%; - padding: 6px 0px 5px; -} - -.capacity-menu-wrapper select { - width: 100%; - background: #edefed; - height: 27px; -} - -/* RESULTS -// ------------------------- */ -#results { - padding: 40px 20px; - background: #edefed; -} - -#hits .hit .pictures-wrapper { - position: relative; -} - -#hits .hit .pictures-wrapper .picture { - width: 100%; -} - -#hits .hit .pictures-wrapper .profile { - position: absolute; - bottom: -16px; - right: 12px; - width: 60px; - border: 4px solid rgba(255, 255, 255, 0.3); - border-radius: 30px; -} - -#hits .hit .infos { - height: 90px; - padding: 16px 20px; -} - -#hits .hit .infos h4 { - font-size: 1em; - font-weight: normal; -} - -#hits .hit .infos p { - font-size: 0.8em; - color: #949697; -} - -#hits .hit .infos em { - font-style: normal; - color: #ff585b; -} - -/* PAGINATION -// ------------------------- */ -.ais-Pagination { - text-align: center; - margin-bottom: 10px; - display: flex; - justify-content: center; -} - -.ais-Pagination .ais-Pagination-item { - display: inline-block; - border: 1px solid; - border-radius: 4px; - padding: 3px; - margin: 1px; - border-color: #ddd; - background: transparent; -} - -.ais-Pagination-item .ais-Pagination-link { - display: block; - color: #ff585b; - line-height: 30px; - width: 30px; - height: 30px; -} - -.ais-Pagination-item.ais-Pagination-item--selected.ais-Pagination-item--page { - background: #ff585b; -} - -.ais-Pagination-item.ais-Pagination-item--selected.ais-Pagination-item--page - .ais-Pagination-link { - color: #ffffff; - border-color: #ff585b; -} - -.ais-Pagination-item--disabled { - visibility: hidden; -} - -.thank-you { - text-align: center; - font-size: 0.8em; -} - -.thank-you a { - color: #ff585b; -} - -/* RHEOSTAT RANGE -// ------------------------- */ -.rheostat-container { - display: flex; - align-items: center; -} -.rheostat { - height: 24px; - position: relative; - overflow: visible; -} - -.rheostat-background { - background: #dce0e0; - height: 2px; - position: relative; - top: 14px; - width: 100%; -} - -.rheostat-values { - display: flex; - font-size: 12px; - justify-content: space-between; - color: rgba(0, 0, 0, 0.6); -} - -.rheostat--disabled .rheostat-progress { - background-color: #edefed; -} - -.rheostat--disabled .rheostat-handle { - cursor: default; -} - -.rheostat-progress { - background-color: #ff585b; - height: 4px; - position: absolute; - top: 13px; -} - -.rheostat-handle { - border: 1px solid #ff585b; - background: #fff; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; - -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - cursor: pointer; - height: 24px; - margin-left: -12px; - position: absolute; - z-index: 2; - width: 24px; - font-size: 0; -} diff --git a/examples/react/tourism/App.js b/examples/react/tourism/App.js deleted file mode 100644 index 97c0e556aa..0000000000 --- a/examples/react/tourism/App.js +++ /dev/null @@ -1,356 +0,0 @@ -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { Component, Fragment } from 'react'; -import { - InstantSearch, - ClearRefinements, - SearchBox, - Pagination, - Highlight, - Configure, - connectHits, - connectNumericMenu, - connectRefinementList, - connectRange, -} from 'react-instantsearch-dom'; -import { - GoogleMapsLoader, - GeoSearch, - Marker, -} from 'react-instantsearch-dom-maps'; -import Rheostat from 'rheostat'; - -import withURLSync from './URLSync'; -import './App.css'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = (props) => ( - - -
- - - -); - -function Header() { - return ( -
- - React InstantSearch - - - BnB - - - -
- ); -} - -function Filters() { - return ( - -
-
-
- - - - -
- -
-
-
-
- -
- - {(google) => ( - - {({ hits }) => ( - - {hits.map((hit) => ( - - ))} - - items.filter((item) => item.id === 'boundingBox') - } - translations={{ - reset: 'Clear the map refinement', - }} - /> - - )} - - )} - -
-
- - ); -} - -function Capacity() { - return ( -
-
Capacity
-
- -
-
- ); -} - -function OptionCapacity({ label, value }) { - return ; -} - -OptionCapacity.propTypes = { - label: PropTypes.string, - value: PropTypes.string, -}; - -const CapacitySelector = connectNumericMenu( - ({ items, currentRefinement, refine }) => { - const selectValue = (e) => refine(e.target.value); - const options = items.map((item) => ( - - )); - - return ( -
- -
- ); - } -); - -function DatesAndGuest() { - return ( -
-
Dates
-
- -
-
- -
-
-
- ); -} - -const RoomType = connectRefinementList(({ items, refine }) => { - const sortedItems = items.sort((i1, i2) => i1.label.localeCompare(i2.label)); - const hitComponents = sortedItems.map((item) => { - const selectedClassName = item.isRefined - ? ' ais-refinement-list--item__active' - : ''; - const itemClassName = `ais-refinement-list--item col-sm-3 ${selectedClassName}`; - return ( -
-
- -
-
- ); - }); - - return ( -
-
Room Type
-
{hitComponents}
-
- ); -}); - -function Price() { - return ( -
-
Price Range
-
- -
-
- ); -} - -const MyHits = connectHits(({ hits }) => { - const hs = hits.map((hit) => ); - return
{hs}
; -}); - -function HitComponent({ hit }) { - return ( -
-
- {hit.name} - {hit.user.user.first_name} -
-
-

- -

- -
-
- ); -} - -function HitDescription({ hit }) { - return ( -

- {hit.room_type} - ,{' '} - -

- ); -} - -HitComponent.propTypes = { - hit: PropTypes.object, -}; - -function Results() { - return ( -
-
- -
-
- -
- Data from airbnb.com, user pics - from randomuser.me -
-
-
- ); -} - -class Range extends Component { - static propTypes = { - min: PropTypes.number, - max: PropTypes.number, - currentRefinement: PropTypes.object, - refine: PropTypes.func.isRequired, - canRefine: PropTypes.bool.isRequired, - }; - - state = { currentValues: { min: this.props.min, max: this.props.max } }; - - componentDidUpdate(prevProps) { - if ( - this.props.canRefine && - (prevProps.currentRefinement.min !== this.props.currentRefinement.min || - prevProps.currentRefinement.max !== this.props.currentRefinement.max) - ) { - this.setState({ - currentValues: { - min: this.props.currentRefinement.min, - max: this.props.currentRefinement.max, - }, - }); - } - } - - onValuesUpdated = (sliderState) => { - this.setState({ - currentValues: { min: sliderState.values[0], max: sliderState.values[1] }, - }); - }; - - onChange = (sliderState) => { - if ( - this.props.currentRefinement.min !== sliderState.values[0] || - this.props.currentRefinement.max !== sliderState.values[1] - ) { - this.props.refine({ - min: sliderState.values[0], - max: sliderState.values[1], - }); - } - }; - - render() { - const { min, max, currentRefinement } = this.props; - const { currentValues } = this.state; - return min !== max ? ( -
- -
-
{currentValues.min}
-
{currentValues.max}
-
-
- ) : null; - } -} - -const ConnectedRange = connectRange(Range); - -export default withURLSync(App); diff --git a/examples/react/tourism/URLSync.js b/examples/react/tourism/URLSync.js deleted file mode 100644 index 1eaa103822..0000000000 --- a/examples/react/tourism/URLSync.js +++ /dev/null @@ -1,56 +0,0 @@ -import qs from 'qs'; -import React, { Component } from 'react'; - -const updateAfter = 700; -const searchStateToURL = (searchState) => - searchState ? `${window.location.pathname}?${qs.stringify(searchState)}` : ''; - -const withURLSync = (App) => - class WithURLSync extends Component { - state = { - searchState: qs.parse(window.location.search.slice(1)), - }; - - componentDidMount() { - window.addEventListener('popstate', this.onPopState); - } - - componentWillUnmount() { - clearTimeout(this.debouncedSetState); - window.removeEventListener('popstate', this.onPopState); - } - - onPopState = ({ state }) => - this.setState({ - searchState: state || {}, - }); - - onSearchStateChange = (searchState) => { - clearTimeout(this.debouncedSetState); - - this.debouncedSetState = setTimeout(() => { - window.history.pushState( - searchState, - null, - searchStateToURL(searchState) - ); - }, updateAfter); - - this.setState({ searchState }); - }; - - render() { - const { searchState } = this.state; - - return ( - - ); - } - }; - -export default withURLSync; diff --git a/examples/react/tourism/index.html b/examples/react/tourism/index.html deleted file mode 100644 index 1b2648df15..0000000000 --- a/examples/react/tourism/index.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - React InstantSearch - Tourism - - - - - -
- - diff --git a/examples/react/tourism/index.js b/examples/react/tourism/index.js deleted file mode 100644 index ae31e41347..0000000000 --- a/examples/react/tourism/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; - -import App from './App'; - -ReactDOM.render(, document.getElementById('root')); diff --git a/examples/react/tourism/package.json b/examples/react/tourism/package.json deleted file mode 100644 index 7eeae33719..0000000000 --- a/examples/react/tourism/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "example-react-instantsearch-tourism", - "version": "15.0.0", - "private": true, - "dependencies": { - "algoliasearch": "4.14.3", - "qs": "6.9.7", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-instantsearch-dom": "6.40.4", - "rheostat": "2.2.0" - } -} diff --git a/global.d.ts b/global.d.ts index eda71845aa..5038ed77bd 100644 --- a/global.d.ts +++ b/global.d.ts @@ -23,9 +23,9 @@ declare module 'algoliasearch-v3' { }; } -// fake typing for legacy modules -declare module 'react-instantsearch-core'; -declare module 'react-instantsearch-dom'; +declare module 'react-instantsearch-core-v6' { + export const InstantSearch: any; +} declare module 'jest-serializer-html/createSerializer' { export default function createSerializer(): jest.SnapshotSerializerPlugin; diff --git a/jest.config.js b/jest.config.js index b3fbb1af55..312d523166 100644 --- a/jest.config.js +++ b/jest.config.js @@ -14,7 +14,7 @@ const config = { '/examples/', '/packages/algoliasearch-helper', '/packages/create-instantsearch-app', - '/packages/react-instantsearch-hooks-router-nextjs', + '/packages/react-instantsearch-router-nextjs', '/__utils__/', ], watchPathIgnorePatterns: [ @@ -36,7 +36,8 @@ const config = { }, moduleFileExtensions: ['tsx', 'ts', 'js', 'vue'], moduleNameMapper: { - '^react-instantsearch-(.*)$': + '^react-instantsearch$': '/packages/react-instantsearch/src/', + '^react-instantsearch-(.*[^v6])$': '/packages/react-instantsearch-$1/src/', '^instantsearch.js$': '/packages/instantsearch.js/src/', }, diff --git a/packages/instantsearch.css/README.md b/packages/instantsearch.css/README.md index f7bd3884d9..980369c567 100644 --- a/packages/instantsearch.css/README.md +++ b/packages/instantsearch.css/README.md @@ -1,6 +1,7 @@ -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +**Table of Contents** _generated with [DocToc](https://github.com/thlorenz/doctoc)_ - [Getting started](#getting-started) - [Installation](#installation) @@ -20,10 +21,7 @@ --- -[![Version][version-svg]][package-url] -[![License][license-image]][license-url] -[![Build Status][ci-svg]][ci-url] -[![Website][website-svg]][website-url] +[![Version][version-svg]][package-url] [![License][license-image]][license-url] [![Build Status][ci-svg]][ci-url] [![Website][website-svg]][website-url] ## Getting started @@ -38,8 +36,8 @@ import 'instantsearch.css/themes/satellite.css'; ``` To learn more about the library, follow the guide on how to style your InstantSearch widgets: + - [InstantSearch.js](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/js/#style-your-widgets) -- [React InstantSearch Hooks](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react-hooks/#style-your-widgets) - [React InstantSearch](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/react/#style-your-widgets) - [Vue InstantSearch](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue/#style-your-widgets) - [Angular InstantSearch](https://www.algolia.com/doc/guides/building-search-ui/widgets/customize-an-existing-widget/angular/#style-your-widgets) @@ -55,6 +53,7 @@ yarn add instantsearch.css ## Available themes InstantSearch.css exposes two themes: + - [Algolia](src/themes/algolia.scss) - [Satellite](src/themes/satellite.scss) @@ -70,14 +69,12 @@ We support the **last two versions of major browsers** (Chrome, Edge, Firefox, S InstantSearch.css is a living standard. This table tracks down the version implemented in each InstantSearch flavor. -| Project | Version | -| ------------------------- | ------- | -| InstantSearch.js | 7 | -| React InstantSearch Hooks | 7 | -| React InstantSearch | 7 | -| Vue InstantSearch | 7 | -| Angular InstantSearch | 7 | - +| Project | Version | +| --------------------- | ------- | +| InstantSearch.js | 7 | +| React InstantSearch | 7 | +| Vue InstantSearch | 7 | +| Angular InstantSearch | 7 | ## Contributing diff --git a/packages/instantsearch.js/src/connectors/breadcrumb/connectBreadcrumb.ts b/packages/instantsearch.js/src/connectors/breadcrumb/connectBreadcrumb.ts index 45e01fd3dc..59720fc306 100644 --- a/packages/instantsearch.js/src/connectors/breadcrumb/connectBreadcrumb.ts +++ b/packages/instantsearch.js/src/connectors/breadcrumb/connectBreadcrumb.ts @@ -188,7 +188,7 @@ const connectBreadcrumb: BreadcrumbConnector = function connectBreadcrumb( function getItems() { // The hierarchicalFacets condition is required for flavors // that render immediately with empty results, without relying - // on init() (like React InstantSearch Hooks). + // on init() (like React InstantSearch). if (!results || state.hierarchicalFacets.length === 0) { return []; } diff --git a/packages/instantsearch.js/src/middlewares/__tests__/createInsightsMiddleware.ts b/packages/instantsearch.js/src/middlewares/__tests__/createInsightsMiddleware.ts index 5209995701..f21dcc2958 100644 --- a/packages/instantsearch.js/src/middlewares/__tests__/createInsightsMiddleware.ts +++ b/packages/instantsearch.js/src/middlewares/__tests__/createInsightsMiddleware.ts @@ -1076,7 +1076,7 @@ See documentation: https://www.algolia.com/doc/guides/building-search-ui/going-f search.start(); - // insights is added *after start*, like in React InstantSearch Hooks + // insights is added *after start*, like in React InstantSearch search.use( createInsightsMiddleware({ insightsClient(eventName, ...args) { @@ -1108,7 +1108,7 @@ See documentation: https://www.algolia.com/doc/guides/building-search-ui/going-f }, }); - // insights is added *after start*, like in React InstantSearch Hooks + // insights is added *after start*, like in React InstantSearch search.use( createInsightsMiddleware({ insightsClient(eventName, ...args) { diff --git a/packages/react-instantsearch-core/CHANGELOG.md b/packages/react-instantsearch-core/CHANGELOG.md index 0dfd2fe8c6..1036d686f4 100644 --- a/packages/react-instantsearch-core/CHANGELOG.md +++ b/packages/react-instantsearch-core/CHANGELOG.md @@ -3,15 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [6.40.4](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.40.3...react-instantsearch-core@6.40.4) (2023-07-25) +## [6.47.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.2...react-instantsearch-hooks@6.47.3) (2023-07-27) -**Note:** Version bump only for package react-instantsearch-core + +### Bug Fixes + +* add a future warning when the package name changes ([#5778](https://github.com/algolia/instantsearch.js/issues/5778)) ([3d22ee4](https://github.com/algolia/instantsearch.js/commit/3d22ee45e1f03a443323a371621262f1fe45e664)) +* **useInstantSearch:** deprecate `use` function ([#5781](https://github.com/algolia/instantsearch.js/issues/5781)) ([ec16c6e](https://github.com/algolia/instantsearch.js/commit/ec16c6e74cc9e364aca47d64983be32bf0cce0fe)) + + + + + +## [6.47.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.1...react-instantsearch-hooks@6.47.2) (2023-07-25) + +**Note:** Version bump only for package react-instantsearch-hooks -## [6.40.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.40.2...react-instantsearch-core@6.40.3) (2023-07-19) +## [6.47.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.0...react-instantsearch-hooks@6.47.1) (2023-07-19) ### Bug Fixes @@ -22,15 +34,38 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.40.1...react-instantsearch-core@6.40.2) (2023-07-18) +# [6.47.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.46.0...react-instantsearch-hooks@6.47.0) (2023-07-18) -**Note:** Version bump only for package react-instantsearch-core +**Note:** Version bump only for package react-instantsearch-hooks +# [6.46.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.45.1...react-instantsearch-hooks@6.46.0) (2023-07-10) + + +### Bug Fixes + +* **url:** base createURL on UiState instead of SearchParameters ([#5696](https://github.com/algolia/instantsearch.js/issues/5696)) ([7e2c8a2](https://github.com/algolia/instantsearch.js/commit/7e2c8a295a6fc5ba36d9482f645ef55b422d5e75)), closes [#5694](https://github.com/algolia/instantsearch.js/issues/5694) + + +### Features + +* **GeoSearch:** expose useGeoSearch() hook in RISH ([#5693](https://github.com/algolia/instantsearch.js/issues/5693)) ([b951b7b](https://github.com/algolia/instantsearch.js/commit/b951b7bcafb384d990ccf02538d9bb9e248a6bba)) + -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.40.0...react-instantsearch-core@6.40.1) (2023-06-20) + + + +## [6.45.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.45.0...react-instantsearch-hooks@6.45.1) (2023-07-04) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +# [6.45.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.3...react-instantsearch-hooks@6.45.0) (2023-06-20) ### Bug Fixes @@ -38,10 +73,42 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline * **dependencies:** update helper requirement ([#5676](https://github.com/algolia/instantsearch.js/issues/5676)) ([c289120](https://github.com/algolia/instantsearch.js/commit/c2891205c1125b1203b3b3db946d57e0fc4e4687)), closes [#5658](https://github.com/algolia/instantsearch.js/issues/5658) +### Features + +* **algoliaAgent:** track Next.js version as Algolia agent ([#5677](https://github.com/algolia/instantsearch.js/issues/5677)) ([b205ac0](https://github.com/algolia/instantsearch.js/commit/b205ac019f79699cd608d63792b8ff5a0832aa7c)) + + + + + +## [6.44.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.2...react-instantsearch-hooks@6.44.3) (2023-06-13) + +**Note:** Version bump only for package react-instantsearch-hooks -# [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.39.1...react-instantsearch-core@6.40.0) (2023-05-16) + + +## [6.44.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.1...react-instantsearch-hooks@6.44.2) (2023-06-05) + + +### Bug Fixes + +* **hooks:** generate version for algoliaAgent in build ([#5655](https://github.com/algolia/instantsearch.js/issues/5655)) ([4d92ac4](https://github.com/algolia/instantsearch.js/commit/4d92ac4769e19e81fb55481aedc71121bef981cb)) + + + + + +## [6.44.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.0...react-instantsearch-hooks@6.44.1) (2023-05-30) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +# [6.44.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.43.0...react-instantsearch-hooks@6.44.0) (2023-05-16) ### Bug Fixes @@ -57,15 +124,137 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline -# [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.38.3...react-instantsearch-core@6.39.1) (2023-01-26) +# [6.43.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.2...react-instantsearch-hooks@6.43.0) (2023-04-24) + + +### Bug Fixes + +* **lifecycle:** prevent extra network requests when unmounting multiple widgets ([#5602](https://github.com/algolia/instantsearch.js/issues/5602)) ([11458ee](https://github.com/algolia/instantsearch.js/commit/11458eee7e7f0f3e9c5f368584a16f58646b1cdd)) + + +### Features + + +* **insights:** add insights option to InstantSearch ([#5488](https://github.com/algolia/instantsearch.js/issues/5488)) ([9031573](https://github.com/algolia/instantsearch.js/commit/9031573807fa6803dcfae9f33d61b8f111f68423)) ([#5578](https://github.com/algolia/instantsearch.js/issues/5578)) ([8fb517f](https://github.com/algolia/instantsearch.js/commit/8fb517f15381ecb32ea00cf4b01a0fd5e70e1d17)) ([#5545](https://github.com/algolia/instantsearch.js/issues/5545)) ([99a0972](https://github.com/algolia/instantsearch.js/commit/99a0972663b8f3284cac3b5621571ced7a33908f)) ([#5493](https://github.com/algolia/instantsearch.js/issues/5493)) ([cff723f](https://github.com/algolia/instantsearch.js/commit/cff723fc95a90ebb2ed14c46c51ab05764835a47)) +* **insights:** always pass Algolia credentials locally ([#5554](https://github.com/algolia/instantsearch.js/issues/5554)) ([654ab81](https://github.com/algolia/instantsearch.js/commit/654ab81e1669354c249710b6756610fba35d54b4)) ([#5558](https://github.com/algolia/instantsearch.js/issues/5558)) ([82144c0](https://github.com/algolia/instantsearch.js/commit/82144c0a0b18e6b47d6f508e5c670a9de274c121)) ([#5529](https://github.com/algolia/instantsearch.js/issues/5529)) ([8537f8f](https://github.com/algolia/instantsearch.js/commit/8537f8f7a10bcaf053ff62180c082e077b1b052d)) +* **insights:** annotate events with algoliaSource ([#5580](https://github.com/algolia/instantsearch.js/issues/5580)) ([c419307](https://github.com/algolia/instantsearch.js/commit/c419307a5f7fe46d5032c9437a17c8e3dad57fe5)) +* **insights:** automatically load search-insights if not passed ([#5484](https://github.com/algolia/instantsearch.js/issues/5484)) ([a85797b](https://github.com/algolia/instantsearch.js/commit/a85797b503edc94e001c5bfb3b754db6cb556943)) +* **insights:** enable default click events on hits and infinite hits ([#5522](https://github.com/algolia/instantsearch.js/issues/5522)) ([271bd12](https://github.com/algolia/instantsearch.js/commit/271bd12e34bc55656976bb53c90282193083eb86)) ([#5527](https://github.com/algolia/instantsearch.js/issues/5527)) ([0e55821](https://github.com/algolia/instantsearch.js/commit/0e558213c807cd17d592fadec052f3d1fc692e6c)) +* **insights:** prevent potential errors ([#5487](https://github.com/algolia/instantsearch.js/issues/5487)) ([33fe510](https://github.com/algolia/instantsearch.js/commit/33fe510307e4b382a5ba1153a0eaf160420acd11)) ([#5606](https://github.com/algolia/instantsearch.js/issues/5606)) ([bdd9290](https://github.com/algolia/instantsearch.js/commit/bdd92901b59ae4e5d7311eadfbf53ed656bbaf4a)) ([#5512](https://github.com/algolia/instantsearch.js/issues/5512)) ([85dfbc9](https://github.com/algolia/instantsearch.js/commit/85dfbc9ebd722fbe6a7e1bd056950fdbcc16d8d9)) +* **metadata:** register metadata around middleware ([#5492](https://github.com/algolia/instantsearch.js/issues/5492)) ([3e72ec8](https://github.com/algolia/instantsearch.js/commit/3e72ec82894a05a071328a4802d2f764233fe005)) + + + + +## [6.42.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.1...react-instantsearch-hooks@6.42.2) (2023-04-11) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +## [6.42.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.0...react-instantsearch-hooks@6.42.1) (2023-03-28) + +### Features + +* **InstantSearch**: warn when an unstable search client is detected ([#5563](https://github.com/algolia/instantsearch.js/issues/5563)) ([0fcf716](https://github.com/algolia/instantsearch/commit/0fcf7162ce77246133c0d4a6ff7ea975ba17cc4c)) + + + +# [6.42.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.41.0...react-instantsearch-hooks@6.42.0) (2023-03-21) + + +### Features + +* **current-refinements:** provide indexId of refinements in transformItems ([#5546](https://github.com/algolia/instantsearch.js/issues/5546)) ([89781db](https://github.com/algolia/instantsearch.js/commit/89781db6cb1d2b8ebbc116e9bcd8a10f646e7baf)) + + + + + +# [6.41.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.1...react-instantsearch-hooks@6.41.0) (2023-03-07) + + +### Features + +* **index:** introduce setIndexUiState ([#5504](https://github.com/algolia/instantsearch.js/issues/5504)) ([c199feb](https://github.com/algolia/instantsearch.js/commit/c199febbc3381df574afbb2504edd7373b32904a)) +* **react:** export `InstantSearchApi` type ([#5518](https://github.com/algolia/instantsearch.js/issues/5518)) ([27b478f](https://github.com/algolia/instantsearch.js/commit/27b478f8f20c4e8835914cceabbdce57ff5d4650)) + + +## Bug Fixes + +* **DynamicWidgets**: prevent non-stable fallbackComponent ([#5532](https://github.com/algolia/instantsearch.js/issues/5532)) ([0625c90](https://github.com/algolia/instantsearch.js/commit/0625c90346e32b926d6ce276a4e0b13d4fa4bf6c)) + + +## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.1...react-instantsearch-hooks@6.40.2) (2023-02-28) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.0...react-instantsearch-hooks@6.40.1) (2023-02-21) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +# [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.3...react-instantsearch-hooks@6.40.0) (2023-02-14) + + +### Features + +* Warn when not using the dedicated Next.js router ([#5432](https://github.com/algolia/instantsearch.js/issues/5432)) ([39b5859](https://github.com/algolia/instantsearch.js/commit/39b5859ba78a5e8472a80e357a35ba900c963b61)) + + +### Bug Fixes + +* Prevent issue where instantsearch instance got created twice in ssr ([#5432](https://github.com/algolia/instantsearch.js/issues/5432)) ([39b5859](https://github.com/algolia/instantsearch.js/commit/39b5859ba78a5e8472a80e357a35ba900c963b61)) + + + +## [6.39.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.2...react-instantsearch-hooks@6.39.3) (2023-02-07) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.1...react-instantsearch-hooks@6.39.2) (2023-01-30) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.0...react-instantsearch-hooks@6.39.1) (2023-01-26) + +**Note:** Version bump only for package react-instantsearch-hooks + + + + + +# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.3...react-instantsearch-hooks@6.39.0) (2023-01-25) + + +### Features +* **react-instantsearch-hooks-web:** Add stats widget and ui component ([#5427](https://github.com/algolia/instantsearch.js/issues/5427)) ([d07cf0d](https://github.com/algolia/instantsearch.js/commit/d07cf0d0310bf4e49d4a4c2142b3783d9bcda79d)) +* **react-instantsearch-hooks:** Add useStats hook ([#5425](https://github.com/algolia/instantsearch.js/issues/5425)) ([772c918](https://github.com/algolia/instantsearch.js/commit/772c918f47aec183af3f1aa78c65505f70dd0088)) +* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) -**Note:** Version bump only for package react-instantsearch-core -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.38.2...react-instantsearch-core@6.38.3) (2023-01-09) +## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.2...react-instantsearch-hooks@6.38.3) (2023-01-09) ### Bug Fixes @@ -76,9 +265,9 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-core@6.38.1...react-instantsearch-core@6.38.2) (2023-01-03) +## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.1...react-instantsearch-hooks@6.38.2) (2023-01-03) -**Note:** Version bump only for package react-instantsearch-core +**Note:** Version bump only for package react-instantsearch-hooks diff --git a/packages/react-instantsearch-core/README.md b/packages/react-instantsearch-core/README.md index 98816fd7a9..31010ec41a 100644 --- a/packages/react-instantsearch-core/README.md +++ b/packages/react-instantsearch-core/README.md @@ -3,11 +3,79 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [react-instantsearch-core](#react-instantsearch-core) + - [Installation](#installation) + - [Getting started](#getting-started) + - [API reference](#api-reference) + - [Documentation](#documentation) + - [Contributing](#contributing) + - [License](#license) # react-instantsearch-core -This is the [React](https://facebook.github.io/react) version of Algolia's `instantsearch` library. +React InstantSearch Core is an open-source UI library for React that lets you quickly build a search interface in your front-end application. -Go to the [React InstantSearch website](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/) or the [React InstantSearch GitHub repository](https://github.com/algolia/instantsearch.js) for more information. +InstantSearch’s goal is to help you implement awesome search experiences as smoothly as possible by providing a [complete search ecosystem](https://algolia.com/doc/guides/getting-started/how-algolia-works/#the-full-ecosystem). InstantSearch tackles an important part of this vast goal by providing front-end primitives that you can assemble into unique search interfaces. + +

+ + Edit on CodeSandbox + +

+ +> Note: `react-instantsearch-core` exports renderless components and hooks which can be used for both web and React Native. If you are using React in a web project, we recommend using the package `react-instantsearch` instead, as it includes complete components that render to the DOM. + +## Installation + +React InstantSearch Core is available on the npm registry. It relies on [`algoliasearch`](https://github.com/algolia/algoliasearch-client-javascript) to communicate with Algolia APIs. + +```sh +yarn add algoliasearch react-instantsearch-core +# or +npm install algoliasearch react-instantsearch-core +``` + +## Getting started + +React InstantSearch Core is a headless React library that lets you create an instant search results experience using Algolia’s search API. + +Check out our [**Getting Started guide**](https://algolia.com/doc/guides/building-search-ui/getting-started/react/) to start implementing a full-featured search experience with React InstantSearch Core. + +## API reference + +Check out the [**API reference**](https://www.algolia.com/doc/api-reference/widgets/react/). + +## Documentation + +The documentation is available on [algolia.com/doc](https://algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/). + +## Contributing + +We welcome all contributors, from casual to regular 💙 + +- **Bug report**. Is something not working as expected? [Send a bug report][contributing-bugreport]. +- **Feature request**. Would you like to add something to the library? [Send a feature request][contributing-featurerequest]. +- **Documentation**. Did you find a typo in the doc? [Open an issue][contributing-newissue] and we'll take care of it. +- **Development**. If you don't know where to start, you can check the open issues that are [tagged easy][contributing-label-easy], the [bugs][contributing-label-bug] or [chores][contributing-label-chore]. + +To start contributing to code, you need to: + +1. [Fork the project](https://help.github.com/articles/fork-a-repo/) +1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) +1. Install the dependencies: `yarn` + +Please read [our contribution process](https://github.com/algolia/instantsearch.js/blob/master/CONTRIBUTING.md) to learn more. + +## License + +React InstantSearch is [MIT licensed](../../LICENSE). + + + +[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch +[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch&title=Feature%20request%3A%20 +[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch +[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch%22 diff --git a/packages/react-instantsearch-hooks-server/global.d.ts b/packages/react-instantsearch-core/global.d.ts similarity index 100% rename from packages/react-instantsearch-hooks-server/global.d.ts rename to packages/react-instantsearch-core/global.d.ts diff --git a/packages/react-instantsearch-core/package.json b/packages/react-instantsearch-core/package.json index 187838203c..364f51475f 100644 --- a/packages/react-instantsearch-core/package.json +++ b/packages/react-instantsearch-core/package.json @@ -1,9 +1,18 @@ { "name": "react-instantsearch-core", - "version": "6.40.4", + "version": "6.47.3", "description": "⚡ Lightning-fast search for React, by Algolia", + "source": "src/index.ts", + "types": "dist/es/index.d.ts", "main": "dist/cjs/index.js", "module": "dist/es/index.js", + "type": "module", + "exports": { + ".": { + "import": "./dist/es/index.js", + "require": "./dist/cjs/index.js" + } + }, "sideEffects": false, "license": "MIT", "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/", @@ -30,20 +39,26 @@ "scripts": { "clean": "rm -rf dist", "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es && yarn build:umd", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", + "build": "yarn build:cjs && yarn build:es && yarn build:umd && yarn build:types", + "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet && ../../scripts/prepare-cjs.sh", "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", "build:umd": "BABEL_ENV=rollup rollup -c rollup.config.js", - "version": "./scripts/version.js" + "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", + "test:exports": "node ./test/module/is-es-module.mjs && node ./test/module/is-cjs-module.cjs", + "version": "./scripts/version.cjs" }, "dependencies": { "@babel/runtime": "^7.1.2", "algoliasearch-helper": "3.14.0", - "prop-types": "^15.6.2", - "react-fast-compare": "^3.0.0" + "instantsearch.js": "4.56.8", + "use-sync-external-store": "^1.0.0" + }, + "devDependencies": { + "@types/use-sync-external-store": "0.0.3", + "react-instantsearch-core-v6": "npm:react-instantsearch-core@6.40.4" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.3.0 < 19" + "react": ">= 16.8.0 < 19" } } diff --git a/packages/react-instantsearch-core/rollup.config.js b/packages/react-instantsearch-core/rollup.config.js index 99dc225193..2e7d9b556a 100644 --- a/packages/react-instantsearch-core/rollup.config.js +++ b/packages/react-instantsearch-core/rollup.config.js @@ -26,7 +26,13 @@ const plugins = [ preferBuiltins: false, extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], }), - commonjs(), + commonjs({ + namedExports: { + '../../node_modules/use-sync-external-store/shim/index.js': [ + 'useSyncExternalStore', + ], + }, + }), globals(), replace({ 'process.env.NODE_ENV': JSON.stringify('production'), diff --git a/packages/react-instantsearch-hooks/scripts/version.cjs b/packages/react-instantsearch-core/scripts/version.cjs similarity index 100% rename from packages/react-instantsearch-hooks/scripts/version.cjs rename to packages/react-instantsearch-core/scripts/version.cjs diff --git a/packages/react-instantsearch-core/scripts/version.js b/packages/react-instantsearch-core/scripts/version.js deleted file mode 100755 index a60770b59c..0000000000 --- a/packages/react-instantsearch-core/scripts/version.js +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env node -/* eslint-disable import/no-commonjs */ - -const fs = require('fs'); -const path = require('path'); - -const version = require('../package.json').version; - -fs.writeFileSync( - path.resolve(__dirname, '../src/core/version.js'), - `export default '${version}';\n` -); diff --git a/packages/react-instantsearch-hooks/src/__tests__/compat.test.tsx b/packages/react-instantsearch-core/src/__tests__/compat.test.tsx similarity index 87% rename from packages/react-instantsearch-hooks/src/__tests__/compat.test.tsx rename to packages/react-instantsearch-core/src/__tests__/compat.test.tsx index 59b0711a3f..2dee61ffdf 100644 --- a/packages/react-instantsearch-hooks/src/__tests__/compat.test.tsx +++ b/packages/react-instantsearch-core/src/__tests__/compat.test.tsx @@ -5,7 +5,7 @@ import { createSearchClient } from '@instantsearch/mocks'; import { render } from '@testing-library/react'; import React from 'react'; -import { InstantSearch as InstantSearchCore } from 'react-instantsearch-core'; +import { InstantSearch as InstantSearchCore } from 'react-instantsearch-core-v6'; import { useSearchBox } from '../connectors/useSearchBox'; import { noop } from '../lib/noop'; @@ -32,7 +32,7 @@ describe('Compat', () => { }).toThrowErrorMatchingInlineSnapshot(` "[InstantSearch] Hooks must be used inside the component. - They are not compatible with the \`react-instantsearch-core\` and \`react-instantsearch-dom\` packages, so make sure to use the component from \`react-instantsearch-hooks\`." + They are not compatible with the \`react-instantsearch-core@6.x\` and \`react-instantsearch-dom\` packages, so make sure to use the component from \`react-instantsearch-core@7.x\`." `); jest.spyOn(console, 'error').mockRestore(); diff --git a/packages/react-instantsearch-hooks/src/__tests__/insights.test.tsx b/packages/react-instantsearch-core/src/__tests__/insights.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/__tests__/insights.test.tsx rename to packages/react-instantsearch-core/src/__tests__/insights.test.tsx diff --git a/packages/react-instantsearch-hooks/src/components/Configure.tsx b/packages/react-instantsearch-core/src/components/Configure.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/Configure.tsx rename to packages/react-instantsearch-core/src/components/Configure.tsx diff --git a/packages/react-instantsearch-hooks/src/components/DynamicWidgets.tsx b/packages/react-instantsearch-core/src/components/DynamicWidgets.tsx similarity index 98% rename from packages/react-instantsearch-hooks/src/components/DynamicWidgets.tsx rename to packages/react-instantsearch-core/src/components/DynamicWidgets.tsx index 8d42da145b..666def0d9b 100644 --- a/packages/react-instantsearch-hooks/src/components/DynamicWidgets.tsx +++ b/packages/react-instantsearch-core/src/components/DynamicWidgets.tsx @@ -34,7 +34,7 @@ export function DynamicWidgets({ warn( Fallback === FallbackComponent.current, - 'The `fallbackComponent` prop of `DynamicWidgets` changed between renders. Please provide a stable reference, as described in https://www.algolia.com/doc/api-reference/widgets/dynamic-facets/react-hooks/#widget-param-fallbackcomponent' + 'The `fallbackComponent` prop of `DynamicWidgets` changed between renders. Please provide a stable reference, as described in https://www.algolia.com/doc/api-reference/widgets/dynamic-facets/react/#widget-param-fallbackcomponent' ); const { attributesToRender } = useDynamicWidgets(props, { diff --git a/packages/react-instantsearch-hooks/src/components/Index.tsx b/packages/react-instantsearch-core/src/components/Index.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/Index.tsx rename to packages/react-instantsearch-core/src/components/Index.tsx diff --git a/packages/react-instantsearch-hooks/src/components/InstantSearch.tsx b/packages/react-instantsearch-core/src/components/InstantSearch.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/InstantSearch.tsx rename to packages/react-instantsearch-core/src/components/InstantSearch.tsx diff --git a/packages/react-instantsearch-hooks/src/components/InstantSearchSSRProvider.tsx b/packages/react-instantsearch-core/src/components/InstantSearchSSRProvider.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/InstantSearchSSRProvider.tsx rename to packages/react-instantsearch-core/src/components/InstantSearchSSRProvider.tsx diff --git a/packages/react-instantsearch-hooks/src/components/InstantSearchServerContext.ts b/packages/react-instantsearch-core/src/components/InstantSearchServerContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/components/InstantSearchServerContext.ts rename to packages/react-instantsearch-core/src/components/InstantSearchServerContext.ts diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/Configure.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/Configure.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/__tests__/Configure.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/Configure.test.tsx diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/DynamicWidgets.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/DynamicWidgets.test.tsx similarity index 99% rename from packages/react-instantsearch-hooks/src/components/__tests__/DynamicWidgets.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/DynamicWidgets.test.tsx index b1ebd295e0..a481cf5238 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/DynamicWidgets.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/DynamicWidgets.test.tsx @@ -405,7 +405,7 @@ describe('DynamicWidgets', () => { expect(() => { rerender(); }).toWarnDev( - '[InstantSearch] The `fallbackComponent` prop of `DynamicWidgets` changed between renders. Please provide a stable reference, as described in https://www.algolia.com/doc/api-reference/widgets/dynamic-facets/react-hooks/#widget-param-fallbackcomponent' + '[InstantSearch] The `fallbackComponent` prop of `DynamicWidgets` changed between renders. Please provide a stable reference, as described in https://www.algolia.com/doc/api-reference/widgets/dynamic-facets/react/#widget-param-fallbackcomponent' ); await waitFor(() => { diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/Index.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/Index.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/__tests__/Index.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/Index.test.tsx diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/InstantSearch.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/InstantSearch.test.tsx similarity index 99% rename from packages/react-instantsearch-hooks/src/components/__tests__/InstantSearch.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/InstantSearch.test.tsx index 3c70486967..79b8456f7b 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/InstantSearch.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/InstantSearch.test.tsx @@ -9,7 +9,7 @@ import userEvent from '@testing-library/user-event'; import { history } from 'instantsearch.js/es/lib/routers'; import { simple } from 'instantsearch.js/es/lib/stateMappings'; import React, { StrictMode, Suspense, version as ReactVersion } from 'react'; -import { SearchBox } from 'react-instantsearch-hooks-web'; +import { SearchBox } from 'react-instantsearch'; import { useRefinementList } from '../../connectors/useRefinementList'; import { warn } from '../../lib/warn'; @@ -108,7 +108,7 @@ describe('InstantSearch', () => { `react-instantsearch (${version})` ); expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch-hooks (${version})` + `react-instantsearch-core (${version})` ); expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( `next.js (${nextVersion})` @@ -574,7 +574,7 @@ describe('InstantSearch', () => { `react-instantsearch (${version})` ); expect(searchClient2.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch-hooks (${version})` + `react-instantsearch-core (${version})` ); }); @@ -591,7 +591,7 @@ describe('InstantSearch', () => { `react-instantsearch (${version})` ); expect(searchClient3.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch-hooks (${version})` + `react-instantsearch-core (${version})` ); }); @@ -631,7 +631,7 @@ describe('InstantSearch', () => { expect(warn).toHaveBeenCalledWith( false, - 'The `searchClient` prop of `` changed between renders, which may cause more search requests than necessary. If this is an unwanted behavior, please provide a stable reference: https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/#widget-param-searchclient' + 'The `searchClient` prop of `` changed between renders, which may cause more search requests than necessary. If this is an unwanted behavior, please provide a stable reference: https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/#widget-param-searchclient' ); }); diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/InstantSearchSSRProvider.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx similarity index 99% rename from packages/react-instantsearch-hooks/src/components/__tests__/InstantSearchSSRProvider.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx index 3deeeca2b6..10f74e60a2 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/InstantSearchSSRProvider.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/InstantSearchSSRProvider.test.tsx @@ -12,7 +12,7 @@ import userEvent from '@testing-library/user-event'; import { history } from 'instantsearch.js/es/lib/routers'; import { simple } from 'instantsearch.js/es/lib/stateMappings'; import React, { StrictMode } from 'react'; -import { Hits, RefinementList, SearchBox } from 'react-instantsearch-hooks-web'; +import { Hits, RefinementList, SearchBox } from 'react-instantsearch'; import { InstantSearch } from '../InstantSearch'; import { InstantSearchSSRProvider } from '../InstantSearchSSRProvider'; diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/InstantSearchServerContext.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/InstantSearchServerContext.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/components/__tests__/InstantSearchServerContext.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/InstantSearchServerContext.test.tsx diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/dispose-start.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/dispose-start.test.tsx similarity index 96% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/dispose-start.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/dispose-start.test.tsx index f29df0b426..76831b2e3e 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/dispose-start.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/dispose-start.test.tsx @@ -6,11 +6,7 @@ import { createSearchClient } from '@instantsearch/mocks'; import { render, waitFor } from '@testing-library/react'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React, { useEffect } from 'react'; -import { - InstantSearch, - SearchBox, - useSearchBox, -} from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox, useSearchBox } from 'react-instantsearch'; describe('routing back and forth to an InstantSearch instance', () => { test('updates the URL after the instance is disposed then restarted', async () => { diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/external-influence.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/external-influence.test.tsx similarity index 95% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/external-influence.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/external-influence.test.tsx index c003eb0731..3b435b91d9 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/external-influence.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/external-influence.test.tsx @@ -6,11 +6,7 @@ import { createSearchClient } from '@instantsearch/mocks'; import { render, waitFor } from '@testing-library/react'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React, { useEffect } from 'react'; -import { - InstantSearch, - SearchBox, - useSearchBox, -} from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox, useSearchBox } from 'react-instantsearch'; describe('routing with external influence', () => { test('keeps on working when the URL is updated by another program', async () => { diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/modal.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/modal.test.tsx similarity index 95% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/modal.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/modal.test.tsx index dccf619390..a11e775927 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/modal.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/modal.test.tsx @@ -7,7 +7,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React from 'react'; -import { InstantSearch, SearchBox } from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox } from 'react-instantsearch'; describe('routing with no navigation', () => { test('cleans the URL when InstantSearch is disposed within the same page', async () => { diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-debounced.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/spa-debounced.test.tsx similarity index 97% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-debounced.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/spa-debounced.test.tsx index 988203177d..3ec72830d8 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-debounced.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/spa-debounced.test.tsx @@ -7,7 +7,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React from 'react'; -import { InstantSearch, SearchBox } from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox } from 'react-instantsearch'; describe('routing with debounced third-party client-side router', () => { test('does not clean the URL after navigating', async () => { diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-replace-state.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/spa-replace-state.test.tsx similarity index 97% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-replace-state.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/spa-replace-state.test.tsx index 293eb52ee5..4c96c520f1 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa-replace-state.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/spa-replace-state.test.tsx @@ -7,7 +7,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React from 'react'; -import { InstantSearch, SearchBox } from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox } from 'react-instantsearch'; describe('routing using `replaceState`', () => { // We can't assert whether another router did update the URL diff --git a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa.test.tsx b/packages/react-instantsearch-core/src/components/__tests__/routing/spa.test.tsx similarity index 96% rename from packages/react-instantsearch-hooks/src/components/__tests__/routing/spa.test.tsx rename to packages/react-instantsearch-core/src/components/__tests__/routing/spa.test.tsx index 31006766c0..1c43580225 100644 --- a/packages/react-instantsearch-hooks/src/components/__tests__/routing/spa.test.tsx +++ b/packages/react-instantsearch-core/src/components/__tests__/routing/spa.test.tsx @@ -7,7 +7,7 @@ import { render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import historyRouter from 'instantsearch.js/es/lib/routers/history'; import React from 'react'; -import { InstantSearch, SearchBox } from 'react-instantsearch-hooks-web'; +import { InstantSearch, SearchBox } from 'react-instantsearch'; describe('routing with third-party client-side router', () => { test('does not clean the URL after navigating', async () => { diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectAutoComplete.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectAutoComplete.js deleted file mode 100644 index cbb7a4124f..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectAutoComplete.js +++ /dev/null @@ -1,264 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectAutoComplete'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectAutoComplete', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides current hits to the component', () => { - const hits = [{}]; - let props = connect.getProvidedProps( - { contextValue }, - {}, - { - results: { hits, page: 0, hitsPerPage: 20 }, - } - ); - expect(props).toEqual({ - hits: [{ __position: 1 }], - currentRefinement: '', - }); - - props = connect.getProvidedProps( - { contextValue }, - { query: 'query' }, - { - results: { hits, page: 0, hitsPerPage: 20 }, - } - ); - expect(props).toEqual({ - hits: [{ __position: 1 }], - currentRefinement: 'query', - }); - - props = connect.getProvidedProps( - { defaultRefinement: 'query', contextValue }, - {}, - { - results: { hits, page: 0, hitsPerPage: 20 }, - } - ); - expect(props).toEqual({ - hits: [{ __position: 1 }], - currentRefinement: 'query', - }); - }); - - it('provides current hits to the component with queryID & position', () => { - const hits = [{}]; - const hitsWithExtraInfo = [{ __queryID: 'zombo.com', __position: 1 }]; - let props = connect.getProvidedProps( - { contextValue }, - {}, - { - results: { hits, page: 0, hitsPerPage: 20, queryID: 'zombo.com' }, - } - ); - expect(props).toEqual({ - hits: hitsWithExtraInfo, - currentRefinement: '', - }); - - props = connect.getProvidedProps( - { contextValue }, - { query: 'query' }, - { - results: { hits, page: 0, hitsPerPage: 20, queryID: 'zombo.com' }, - } - ); - expect(props).toEqual({ - hits: hitsWithExtraInfo, - currentRefinement: 'query', - }); - - props = connect.getProvidedProps( - { defaultRefinement: 'query', contextValue }, - {}, - { - results: { hits, page: 0, hitsPerPage: 20, queryID: 'zombo.com' }, - } - ); - expect(props).toEqual({ - hits: hitsWithExtraInfo, - currentRefinement: 'query', - }); - }); - - it('refines the query parameter', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { contextValue }, - { query: 'bar' } - ); - expect(params.query).toBe('bar'); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - query: 'yep', - page: 1, - }); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue }, - { - query: { searchState: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ another: { searchState: 'searchState' } }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides current hits to the component', () => { - const firstHits = [{}]; - const secondHits = [{}]; - const firstHitsWithExtraInfo = [ - { __queryID: 'zombo.com', __position: 1 }, - ]; - const secondHitsWithExtraInfo = [ - { __queryID: 'html5zombo.com', __position: 1 }, - ]; - let props = connect.getProvidedProps( - { contextValue, indexContextValue }, - {}, - { - results: { - first: { - hits: firstHits, - page: 0, - hitsPerPage: 20, - queryID: 'zombo.com', - }, - second: { - hits: secondHits, - page: 0, - hitsPerPage: 20, - queryID: 'html5zombo.com', - }, - }, - } - ); - expect(props).toEqual({ - hits: [ - { - hits: firstHitsWithExtraInfo, - index: 'first', - }, - { - hits: secondHitsWithExtraInfo, - - index: 'second', - }, - ], - currentRefinement: '', - }); - - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - { indices: { second: { query: 'query' } } }, - { - results: { - first: { - hits: firstHits, - page: 0, - hitsPerPage: 20, - queryID: 'zombo.com', - }, - second: { - hits: secondHits, - page: 0, - hitsPerPage: 20, - queryID: 'html5zombo.com', - }, - }, - } - ); - expect(props).toEqual({ - hits: [ - { hits: firstHitsWithExtraInfo, index: 'first' }, - { hits: secondHitsWithExtraInfo, index: 'second' }, - ], - currentRefinement: 'query', - }); - - props = connect.getProvidedProps( - { defaultRefinement: 'query', contextValue, indexContextValue }, - {}, - { - results: { - first: { - hits: firstHits, - page: 0, - hitsPerPage: 20, - queryID: 'zombo.com', - }, - second: { - hits: secondHits, - page: 0, - hitsPerPage: 20, - queryID: 'html5zombo.com', - }, - }, - } - ); - expect(props).toEqual({ - hits: [ - { hits: firstHitsWithExtraInfo, index: 'first' }, - { hits: secondHitsWithExtraInfo, index: 'second' }, - ], - currentRefinement: 'query', - }); - }); - - it('refines the query parameter', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { contextValue, indexContextValue }, - { indices: { second: { query: 'bar' } } } - ); - expect(params.query).toBe('bar'); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue, indexContextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { second: { query: 'yep', page: 1 } }, - }); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue, indexContextValue }, - { - indices: { second: { query: '' } }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: {} }, - another: { searchState: 'searchState' }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectBreadcrumb.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectBreadcrumb.js deleted file mode 100644 index 141fc438dd..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectBreadcrumb.js +++ /dev/null @@ -1,279 +0,0 @@ -import connect from '../connectBreadcrumb'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; - -describe('connectBreadcrumb', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - const results = { - getFacetValues: jest.fn(), - getFacetByName: () => true, - hits: [], - }; - - results.getFacetValues.mockImplementationOnce(() => ({})); - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue }, - { hierarchicalMenu: { ok: 'wat' } }, - { results } - ); - expect(props).toEqual({ - canRefine: false, - items: [], - }); - - results.getFacetValues.mockClear(); - results.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - isRefined: true, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - isRefined: true, - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - isRefined: false, - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - isRefined: false, - count: 10, - }, - ], - })); - props = connect.getProvidedProps( - { - attributes: ['ok'], - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - }, - { - label: 'wot', - value: 'wat > wot', - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - label: 'wat', - value: 'wat', - }, - { - label: 'wot', - value: 'wat > wot', - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { attributes: ['ok'], contextValue }, - { otherKey: 'val', hierarchicalMenu: { otherKey: 'val' } }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - const results = { - second: { - getFacetValues: jest.fn(), - getFacetByName: () => true, - }, - }; - - results.second.getFacetValues.mockImplementationOnce(() => ({})); - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - { indices: { second: { hierarchicalMenu: { ok: 'wat' } } } }, - { results } - ); - expect(props).toEqual({ - canRefine: false, - items: [], - }); - - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - {}, - {} - ); - expect(props).toEqual({ - canRefine: false, - items: [], - }); - - results.second.getFacetValues.mockClear(); - results.second.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - isRefined: true, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - isRefined: true, - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - isRefined: false, - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - isRefined: false, - count: 10, - }, - ], - })); - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - }, - { - label: 'wot', - value: 'wat > wot', - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue, indexContextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - label: 'wat', - value: 'wat', - }, - { - label: 'wot', - value: 'wat > wot', - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { - attributes: ['ok'], - contextValue, - indexContextValue, - }, - { - indices: { - first: { otherKey: 'val1', hierarchicalMenu: { otherKey: 'val1' } }, - second: { otherKey: 'val', hierarchicalMenu: { otherKey: 'val' } }, - }, - }, - 'yep' - ); - - expect(nextState).toEqual({ - indices: { - first: { - otherKey: 'val1', - hierarchicalMenu: { otherKey: 'val1' }, - }, - second: { - page: 1, - otherKey: 'val', - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - - nextState = connect.refine( - { - attributes: ['ok'], - contextValue, - indexContextValue: { targetedIndex: 'second' }, - }, - { - indices: { - first: { page: 1, hierarchicalMenu: { otherKey: 'val1' } }, - second: { - otherKey: 'val', - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }, - 'yep' - ); - - expect(nextState).toEqual({ - indices: { - first: { page: 1, hierarchicalMenu: { otherKey: 'val1' } }, - second: { - page: 1, - otherKey: 'val', - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigure.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigure.js deleted file mode 100644 index 3c1f0a5a36..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigure.js +++ /dev/null @@ -1,271 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectConfigure'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectConfigure', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('propagates the props to the SearchParameters without children & contextValue', () => { - const searchParameters = connect.getSearchParameters.call( - {}, - new SearchParameters(), - { distinct: 1, whatever: 'please', children: 'whatever', contextValue }, - {} - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - distinct: 1, - whatever: 'please', - }) - ); - expect(searchParameters).not.toEqual( - expect.objectContaining({ - children: 'whatever', - contextValue, - }) - ); - expect(searchParameters.distinct).toEqual(1); - expect(searchParameters.whatever).toEqual('please'); - expect(searchParameters.children).toBeUndefined(); - expect(searchParameters.contextValue).toBeUndefined(); - }); - - it('calling transitionState should add configure parameters to the search state', () => { - const instance = {}; - let searchState = connect.transitionState.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue, - }, - {}, - {} - ); - expect(searchState).toEqual({ - configure: { distinct: 1, whatever: 'please' }, - }); - - searchState = connect.transitionState.call( - instance, - { whatever: 'other', children: 'whatever', contextValue }, - { configure: { distinct: 1, whatever: 'please' } }, - { configure: { distinct: 1, whatever: 'please' } } - ); - - expect(searchState).toEqual({ configure: { whatever: 'other' } }); - }); - - it('calling cleanUp should remove configure parameters from the search state', () => { - let searchState = connect.cleanUp.call( - {}, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue, - }, - { - configure: { - distinct: 1, - whatever: 'please', - another: 'parameters', - }, - } - ); - expect(searchState).toEqual({ configure: { another: 'parameters' } }); - - searchState = connect.cleanUp.call( - {}, - { distinct: 1, whatever: 'please', children: 'whatever', contextValue }, - { configure: { distinct: 1, whatever: 'please' } } - ); - expect(searchState).toEqual({ configure: {} }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('propagates the props to the SearchParameters without children', () => { - const searchParameters = connect.getSearchParameters.call( - {}, - new SearchParameters(), - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue, - indexContextValue, - }, - {} - ); - expect(searchParameters.distinct).toEqual(1); - expect(searchParameters.whatever).toEqual('please'); - expect(searchParameters.children).toBeUndefined(); - expect(searchParameters.contextValue).toBeUndefined(); - expect(searchParameters.indexContextValue).toBeUndefined(); - }); - - it('calling transitionState should add configure parameters to the search state', () => { - const instance = {}; - let searchState = connect.transitionState.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue, - indexContextValue, - }, - {}, - {} - ); - expect(searchState).toEqual({ - indices: { second: { configure: { distinct: 1, whatever: 'please' } } }, - }); - - searchState = connect.transitionState.call( - instance, - { - whatever: 'other', - children: 'whatever', - contextValue, - indexContextValue, - }, - { - indices: { - second: { configure: { distinct: 1, whatever: 'please' } }, - }, - }, - { - indices: { - second: { configure: { distinct: 1, whatever: 'please' } }, - }, - } - ); - - expect(searchState).toEqual({ - indices: { second: { configure: { whatever: 'other' } } }, - }); - - searchState = connect.transitionState.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { indices: { second: { configure: { whatever: 'other' } } } }, - { indices: { second: { configure: { whatever: 'other' } } } } - ); - - expect(searchState).toEqual({ - indices: { - second: { configure: { whatever: 'other' } }, - first: { configure: { distinct: 1, whatever: 'please' } }, - }, - }); - - searchState = connect.transitionState.call( - instance, - { - whatever: 'other', - children: 'whatever', - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { - indices: { - second: { configure: { whatever: 'other' } }, - first: { configure: { distinct: 1, whatever: 'please' } }, - }, - }, - { - indices: { - second: { configure: { whatever: 'other' } }, - first: { configure: { distinct: 1, whatever: 'please' } }, - }, - } - ); - - expect(searchState).toEqual({ - indices: { - second: { configure: { whatever: 'other' } }, - first: { configure: { whatever: 'other' } }, - }, - }); - }); - - it('calling cleanUp should remove configure parameters from the search state', () => { - const instance = {}; - let searchState = connect.cleanUp.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue, - indexContextValue, - }, - { - indices: { - second: { configure: { whatever: 'other' } }, - first: { configure: { distinct: 1, whatever: 'please' } }, - }, - } - ); - expect(searchState).toEqual({ - indices: { - first: { configure: { distinct: 1, whatever: 'please' } }, - second: { configure: {} }, - }, - }); - - searchState = connect.cleanUp.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { - indices: { - first: { configure: { distinct: 1, whatever: 'please' } }, - second: { configure: {} }, - }, - } - ); - expect(searchState).toEqual({ - indices: { first: { configure: {} }, second: { configure: {} } }, - }); - - searchState = connect.cleanUp.call( - instance, - { - distinct: 1, - whatever: 'please', - children: 'whatever', - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { indices: {} } - ); - expect(searchState).toEqual({ - indices: { - first: { configure: {} }, - }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigureRelatedItems.ts b/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigureRelatedItems.ts deleted file mode 100644 index 411276cbfd..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectConfigureRelatedItems.ts +++ /dev/null @@ -1,583 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connectConfigureRelatedItems from '../connectConfigureRelatedItems'; - -import type { PlainSearchParameters } from 'algoliasearch-helper'; - -jest.mock('../../core/createConnector', () => (x: any) => x); -const connect = connectConfigureRelatedItems as any; - -const hit = { - objectID: '1', - name: 'Amazon - Fire TV Stick with Alexa Voice Remote - Black', - description: - 'Enjoy smart access to videos, games and apps with this Amazon Fire TV stick.', - brand: 'Amazon', - categories: ['TV & Home Theater', 'Streaming Media Players'], - hierarchicalCategories: { - lvl0: 'TV & Home Theater', - lvl1: 'TV & Home Theater > Streaming Media Players', - }, - price: 39.99, - free_shipping: false, - rating: 4, - _snippetResult: { - description: { - value: - 'Enjoy smart access to videos, games and apps with this Amazon Fire TV stick. Its […]', - matchLevel: 'none', - }, - }, - _highlightResult: { - description: { - value: - 'Enjoy smart access to videos, games and apps with this Amazon Fire TV stick. Its […]', - matchLevel: 'none', - matchedWords: [], - }, - }, -}; - -describe('connectConfigure', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - const defaultProps = { - transformSearchParameters: (x: PlainSearchParameters) => x, - contextValue, - }; - - it('does not provide props', () => { - const providedProps = connect.getProvidedProps({ contextValue }, null, { - results: {}, - }); - - expect(providedProps).toEqual({}); - }); - - it('sets the optionalFilters search parameter based on matchingPatterns', () => { - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - } - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }) - ); - }); - - it('sets the optionalFilters search parameter based on matchingPatterns with nested attributes', () => { - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - 'hierarchicalCategories.lvl0': { score: 2 }, - }, - } - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - 'hierarchicalCategories.lvl0:TV & Home Theater', - ], - }) - ); - }); - - it('sets transformed search parameters based on transformSearchParameters', () => { - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - transformSearchParameters(parameters: PlainSearchParameters) { - return { - ...parameters, - optionalWords: hit.name.split(' '), - }; - }, - } - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - optionalWords: [ - 'Amazon', - '-', - 'Fire', - 'TV', - 'Stick', - 'with', - 'Alexa', - 'Voice', - 'Remote', - '-', - 'Black', - ], - }) - ); - }); - - it('filters out and warns for incorrect optionalFilters value type', () => { - // We need to simulate being in development mode and to mock the global console object - // in this test to assert that development warnings are displayed correctly. - const originalNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'development'; - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - rating: { score: 1 }, // `rating` is a number, which is not supported by the `optionalFilters` API - brand: { score: 3 }, - categories: { score: 2 }, - }, - } - ); - - expect(warnSpy).toHaveBeenCalledTimes(1); - expect(warnSpy).toHaveBeenCalledWith( - 'The `matchingPatterns` option returned a value of type Number for the "rating" key. This value was not sent to Algolia because `optionalFilters` only supports strings and array of strings.\n\n' + - 'You can remove the "rating" key from the `matchingPatterns` option.\n\n' + - 'See https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/' - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }) - ); - - process.env.NODE_ENV = originalNodeEnv; - warnSpy.mockRestore(); - }); - - it('calling transitionState should add configure parameters to the search state', () => { - const instance = {}; - - let searchState = connect.transitionState.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - {}, - {} - ); - - expect(searchState).toEqual({ - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }, - }); - - searchState = connect.transitionState.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - }, - }, - { configure: { facets: ['categories'] } }, - { configure: { facets: ['categories'] } } - ); - - expect(searchState).toEqual({ - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: ['brand:Amazon'], - facets: ['categories'], - }, - }); - }); - - it('calling cleanUp should remove configure parameters from the search state', () => { - const instance = {}; - - // Running `transitionState` allows to set previous search parameters - // in the connector state. - let searchState = connect.transitionState.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - {}, - {} - ); - - searchState = connect.cleanUp.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - { - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: ['brand:Amazon'], - facets: ['categories'], - }, - } - ); - - expect(searchState).toEqual({ - configure: { - facets: ['categories'], - }, - }); - - searchState = connect.cleanUp.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - { - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: ['brand:Amazon'], - }, - } - ); - - expect(searchState).toEqual({ configure: {} }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - const defaultProps = { - transformSearchParameters: (x: PlainSearchParameters) => x, - contextValue, - indexContextValue, - }; - - it('does not provide props', () => { - const providedProps = connect.getProvidedProps({ contextValue }, null, { - results: {}, - }); - - expect(providedProps).toEqual({}); - }); - - it('sets the optionalFilters search parameter based on matchingPatterns', () => { - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - } - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }) - ); - }); - - it('sets transformed search parameters based on transformSearchParameters', () => { - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - transformSearchParameters(parameters: PlainSearchParameters) { - return { - ...parameters, - optionalWords: hit.name.split(' '), - }; - }, - } - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - optionalWords: [ - 'Amazon', - '-', - 'Fire', - 'TV', - 'Stick', - 'with', - 'Alexa', - 'Voice', - 'Remote', - '-', - 'Black', - ], - }) - ); - }); - - it('filters out and warns for incorrect optionalFilters value type', () => { - // We need to simulate being in development mode and to mock the global console object - // in this test to assert that development warnings are displayed correctly. - const originalNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'development'; - const warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {}); - - const searchParameters = connect.getSearchParameters.call( - { contextValue }, - new SearchParameters(), - { - ...defaultProps, - hit, - matchingPatterns: { - rating: { score: 1 }, // `rating` is a number, which is not supported by the `optionalFilters` API - brand: { score: 3 }, - categories: { score: 2 }, - }, - } - ); - - expect(warnSpy).toHaveBeenCalledTimes(1); - expect(warnSpy).toHaveBeenCalledWith( - 'The `matchingPatterns` option returned a value of type Number for the "rating" key. This value was not sent to Algolia because `optionalFilters` only supports strings and array of strings.\n\n' + - 'You can remove the "rating" key from the `matchingPatterns` option.\n\n' + - 'See https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/' - ); - - expect(searchParameters).toEqual( - expect.objectContaining({ - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }) - ); - - process.env.NODE_ENV = originalNodeEnv; - warnSpy.mockRestore(); - }); - - it('calling transitionState should add configure parameters to the search state', () => { - const instance = {}; - - const searchState = connect.transitionState.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - {}, - {} - ); - - expect(searchState).toEqual({ - indices: { - second: { - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: [ - 'brand:Amazon', - [ - 'categories:TV & Home Theater', - 'categories:Streaming Media Players', - ], - ], - }, - }, - }, - }); - }); - - it('calling cleanUp should remove configure parameters from the search state', () => { - const instance = {}; - - // Running `transitionState` allows to set previous search parameters - // in the connector state. - let searchState = connect.transitionState.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - {}, - {} - ); - - searchState = connect.cleanUp.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - { - indices: { - second: { - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: ['brand:Amazon'], - facets: ['categories'], - }, - }, - }, - } - ); - - expect(searchState).toEqual({ - indices: { - second: { - configure: { - facets: ['categories'], - }, - }, - }, - }); - - searchState = connect.cleanUp.call( - instance, - { - ...defaultProps, - hit, - matchingPatterns: { - brand: { score: 3 }, - categories: { score: 2 }, - }, - }, - { - indices: { - second: { - configure: { - facetFilters: ['objectID:-1'], - sumOrFiltersScores: true, - optionalFilters: ['brand:Amazon'], - }, - }, - }, - } - ); - - expect(searchState).toEqual({ indices: { second: { configure: {} } } }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectCurrentRefinements.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectCurrentRefinements.js deleted file mode 100644 index 935804f899..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectCurrentRefinements.js +++ /dev/null @@ -1,124 +0,0 @@ -import connect from '../connectCurrentRefinements'; - -jest.mock('../../core/createConnector', () => (x) => x); - -const { refine } = connect; - -describe('connectCurrentRefinements', () => { - it('provides the correct props to the component', () => { - let props = connect.getProvidedProps({}, null, null, [ - { items: [{ label: 'one' }], id: 1, index: 'something' }, - { items: [{ label: 'two' }], id: 2, index: 'something' }, - { items: [{ label: 'three' }], id: 'query', index: 'something' }, - ]); - expect(props.items).toEqual([ - { id: 1, index: 'something', label: 'one' }, - { id: 2, index: 'something', label: 'two' }, - ]); - - props = connect.getProvidedProps({}, null, null, []); - expect(props).toEqual({ canRefine: false, items: [] }); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps({ transformItems }, null, null, [ - { items: [{ label: 'one' }], id: 1, index: 'something' }, - { items: [{ label: 'two' }], id: 2, index: 'something' }, - { items: [{ label: 'three' }], id: 3, index: 'something' }, - ]); - expect(transformItems.mock.calls[0][0]).toEqual([ - { id: 1, index: 'something', label: 'one' }, - { id: 2, index: 'something', label: 'two' }, - { id: 3, index: 'something', label: 'three' }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('provides the query if clearsQuery props is true', () => { - const results = { - index: { - query: 'query', - }, - }; - - const props = connect.getProvidedProps( - { clearsQuery: true }, - null, - { results }, - [{ items: [{ currentRefinement: 'query' }], id: 'query', index: '' }] - ); - - expect(props.items).toEqual([ - { currentRefinement: 'query', id: 'query', index: '' }, - ]); - }); - - it('dont provide the query if clearsQuery props is true but the current refinement is an empty string', () => { - const results = { - index: { - query: '', - }, - }; - - const props = connect.getProvidedProps( - { clearsQuery: true }, - null, - { results }, - [{ items: [{ currentRefinement: '' }], id: 'query' }] - ); - - expect(props.items).toEqual([]); - }); - - it('refine applies the selected filters clear method on searchState', () => { - let searchState = refine({}, { wow: 'sweet' }, [ - { - value: (nextState) => ({ ...nextState, cool: 'neat' }), - }, - ]); - expect(searchState).toEqual({ wow: 'sweet', cool: 'neat' }); - - searchState = refine({ clearsQuery: true }, { wow: 'sweet' }, [ - { - value: (nextState) => ({ ...nextState, cool: 'neat' }), - }, - ]); - expect(searchState).toEqual({ wow: 'sweet', cool: 'neat' }); - }); - - it('deduplicates entries with transformItems', () => { - const transformItems = (items) => - items - .map(({ id, index, ...rest }) => ({ - __dedupe: `${index}.${id}`, - id, - index, - ...rest, - })) - .sort((a, b) => a.id > b.__dedupe) - .filter( - (current, index, array) => - index === 0 || current.__dedupe !== array[index - 1].__dedupe - ) - .map(({ __dedupe, ...item }) => item); - - const props = connect.getProvidedProps({ transformItems }, null, null, [ - { items: [{ label: 'abra' }], id: 1, index: 'something' }, - { items: [{ label: 'cadabra' }], id: 2, index: 'something' }, - { items: [{ label: 'cadabra' }], id: 2, index: 'something' }, - ]); - - expect(props.items).toEqual([ - { id: 1, index: 'something', label: 'abra' }, - { id: 2, index: 'something', label: 'cadabra' }, - ]); - }); - - it('computes canRefine based on the length of the transformed items list', () => { - const transformItems = () => []; - const props = connect.getProvidedProps({ transformItems }, null, null, [ - { items: [{ label: 'one' }], id: 1, index: 'something' }, - ]); - - expect(props.canRefine).toEqual(false); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectDynamicWidgets.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectDynamicWidgets.js deleted file mode 100644 index 313892cc39..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectDynamicWidgets.js +++ /dev/null @@ -1,504 +0,0 @@ -import { SearchResults, SearchParameters } from 'algoliasearch-helper'; - -import connector from '../connectDynamicWidgets'; - -jest.mock('../../core/createConnector', () => (x) => x); - -const EMPTY_RESPONSE = { - results: [ - { - hits: [], - nbHits: 0, - page: 0, - nbPages: 0, - hitsPerPage: 20, - exhaustiveNbHits: true, - query: '', - queryAfterRemoval: '', - params: - 'highlightPreTag=%3Cais-highlight-0000000000%3E&highlightPostTag=%3C%2Fais-highlight-0000000000%3E&query=&facets=%5B%5D&tagFilters=', - index: 'instant_search', - processingTimeMS: 2, - }, - ], -}; - -describe('connectDynamicWidgets', () => { - const empty = {}; - const contextValue = { - mainTargetedIndex: 'index', - }; - - describe('getSearchParameters', () => { - it('sets facets * and maxValuesPerFacet by default', () => { - const props = { - contextValue, - ...connector.defaultProps, - }; - const searchState = {}; - - const actual = connector.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(actual).toEqual( - new SearchParameters({ - facets: ['*'], - maxValuesPerFacet: 20, - }) - ); - }); - - it('gets added onto existing parameters', () => { - const props = { - contextValue, - ...connector.defaultProps, - }; - const searchState = {}; - - const actual = connector.getSearchParameters( - new SearchParameters({ - facets: ['123'], - maxValuesPerFacet: 1000, - }), - props, - searchState - ); - - expect(actual).toEqual( - new SearchParameters({ - facets: ['123', '*'], - maxValuesPerFacet: 1000, - }) - ); - }); - - it('allows override of facets and maxValuesPerFacet', () => { - const props = { - contextValue, - ...connector.defaultProps, - facets: ['lol'], - maxValuesPerFacet: 1000, - }; - const searchState = {}; - - const actual = connector.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(actual).toEqual( - new SearchParameters({ - facets: ['lol'], - maxValuesPerFacet: 1000, - }) - ); - }); - }); - - describe('single index', () => { - const createSingleIndexSearchResults = (result = {}, state) => ({ - results: new SearchResults(new SearchParameters(state), [ - { - ...EMPTY_RESPONSE.results[0], - ...result, - }, - ]), - }); - - describe('getProvidedProps', () => { - it('empty results', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = { - attributesToRender: [], - }; - - expect(actual).toEqual(expectation); - }); - - it('attributesToRender is the return value of transformItems', () => { - const returnValue = ['test1', 'test2']; - const props = { contextValue, transformItems: () => returnValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(returnValue); - }); - - it('default items is []', () => { - const props = { contextValue, transformItems: (items) => items }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual([]); - }); - - it('reads from facetOrdering by default', () => { - const props = { - contextValue, - ...connector.defaultProps, - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - renderingContent: { - facetOrdering: { facets: { order: ['one', 'two'] } }, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(['one', 'two']); - }); - - it('transformItems gets called with results', () => { - const props = { - contextValue, - transformItems: jest.fn((items) => items), - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - userData: [{ MOCK_FACET_ORDER: ['one', 'two'] }], - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(props.transformItems).toHaveBeenCalledTimes(1); - expect(props.transformItems).toHaveBeenCalledWith([], { - results: searchResults.results, - }); - - expect(actual.attributesToRender).toEqual([]); - }); - - it('userData is usable as a source for transformItems', () => { - const props = { - contextValue, - transformItems: (_items, { results }) => - results.userData[0].MOCK_FACET_ORDER, - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - userData: [{ MOCK_FACET_ORDER: ['one', 'two'] }], - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(['one', 'two']); - }); - - it('fails when a non-star facet is given', () => { - const props = { - contextValue, - ...connector.defaultProps, - facets: ['lol'], - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({}); - - expect(() => - connector.getProvidedProps(props, searchState, searchResults) - ).toThrowErrorMatchingInlineSnapshot( - `"The \`facets\` prop only accepts [] or [\\"*\\"], you passed [\\"lol\\"]"` - ); - }); - - it('fails when a multiple star facets are given', () => { - const props = { - contextValue, - ...connector.defaultProps, - facets: ['*', '*'], - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({}); - - expect(() => - connector.getProvidedProps(props, searchState, searchResults) - ).toThrowErrorMatchingInlineSnapshot( - `"The \`facets\` prop only accepts [] or [\\"*\\"], you passed [\\"*\\",\\"*\\"]"` - ); - }); - - it('does not fail when only star facet is given', () => { - const props = { - contextValue, - ...connector.defaultProps, - facets: ['*'], - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({}); - - expect(() => - connector.getProvidedProps(props, searchState, searchResults) - ).not.toThrow(); - }); - - it('does not fail when no facet is given', () => { - const props = { - contextValue, - ...connector.defaultProps, - facets: [], - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({}); - - expect(() => - connector.getProvidedProps(props, searchState, searchResults) - ).not.toThrow(); - }); - - it('warns if maxValuesPerFacet is lower than set by another widget', () => { - const spy = jest.spyOn(console, 'warn'); - const props = { - contextValue, - ...connector.defaultProps, - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults( - {}, - new SearchParameters({ maxValuesPerFacet: 100 }) - ); - - connector.getProvidedProps(props, searchState, searchResults); - - expect(spy).toHaveBeenCalledWith( - 'The maxValuesPerFacet set by dynamic widgets (20) is smaller than one of the limits set by a widget (100). This causes a mismatch in query parameters and thus an extra network request when that widget is mounted.' - ); - }); - - it('warns if >20 facets are displayed due to implicit *', () => { - const spy = jest.spyOn(console, 'warn'); - const props = { - contextValue, - transformItems: (_items, { results }) => - results.userData[0].MOCK_FACET_ORDER, - }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - userData: [ - { - MOCK_FACET_ORDER: Array.from( - { length: 21 }, - (_, i) => `item${i}` - ), - }, - ], - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(spy).toHaveBeenCalledWith( - 'More than 20 facets are requested to be displayed without explicitly setting which facets to retrieve. This could have a performance impact. Set "facets" to [] to do two smaller network requests, or explicitly to [\'*\'] to avoid this warning.' - ); - - expect(actual.attributesToRender).toEqual([ - 'item0', - 'item1', - 'item2', - 'item3', - 'item4', - 'item5', - 'item6', - 'item7', - 'item8', - 'item9', - 'item10', - 'item11', - 'item12', - 'item13', - 'item14', - 'item15', - 'item16', - 'item17', - 'item18', - 'item19', - 'item20', - ]); - }); - }); - }); - - describe('multi index', () => { - const indexContextValue = { targetedIndex: 'second' }; - - const createMultiIndexSearchState = (state = {}) => ({ - indices: { - second: state, - }, - }); - - const createMultiIndexSearchResults = (result = {}, state) => ({ - results: { - second: new SearchResults(new SearchParameters(state), [ - { - ...EMPTY_RESPONSE.results[0], - ...result, - }, - ]), - }, - }); - - describe('getProvidedProps', () => { - it('empty results', () => { - const searchState = createMultiIndexSearchState(); - const props = { contextValue, indexContextValue }; - - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = { - attributesToRender: [], - }; - - expect(actual).toEqual(expectation); - }); - - it('attributesToRender is the return value of transformItems', () => { - const returnValue = ['one', 'two']; - const props = { - contextValue, - indexContextValue, - transformItems: () => returnValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(returnValue); - }); - - it('default items is []', () => { - const props = { - contextValue, - indexContextValue, - transformItems: (items) => items, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual([]); - }); - - it('reads from facetOrdering by default', () => { - const props = { - contextValue, - indexContextValue, - transformItems: (items) => items, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - renderingContent: { - facetOrdering: { facets: { order: ['one', 'two'] } }, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(['one', 'two']); - }); - - it('transformItems gets called with results', () => { - const props = { - contextValue, - indexContextValue, - transformItems: jest.fn((items) => items), - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(props.transformItems).toHaveBeenCalledTimes(1); - expect(props.transformItems).toHaveBeenCalledWith([], { - results: searchResults.results.second, - }); - - expect(actual.attributesToRender).toEqual([]); - }); - - it('userData is usable as a source for transformItems', () => { - const props = { - contextValue, - indexContextValue, - transformItems: (_items, { results }) => - results.userData[0].MOCK_FACET_ORDER, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - userData: [{ MOCK_FACET_ORDER: ['one', 'two'] }], - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.attributesToRender).toEqual(['one', 'two']); - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectGeoSearch.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectGeoSearch.js deleted file mode 100644 index 25f78c2c60..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectGeoSearch.js +++ /dev/null @@ -1,1434 +0,0 @@ -import { SearchResults, SearchParameters } from 'algoliasearch-helper'; - -import connector from '../connectGeoSearch'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectGeoSearch', () => { - const empty = {}; - - describe('single index', () => { - const contextValue = { - mainTargetedIndex: 'index', - }; - - const createSingleIndexSearchResults = (hits = [], state) => ({ - results: new SearchResults(new SearchParameters(state), [ - { - hits, - }, - ]), - }); - - describe('getProvidedProps', () => { - it('expect to return default provided props', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = { - hits: [], - position: undefined, - currentRefinement: undefined, - isRefinedWithMap: false, - }; - - expect(actual).toEqual(expectation); - }); - - describe('hits', () => { - it('expect to return hits when we have results', () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - expect(actual.hits).toEqual(expectation); - }); - - it('expect to return hits with only "_geoloc" when we have results', () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: false }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = [ - { objectID: '123', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - expect(actual.hits).toEqual(expectation); - }); - - it("expect to return empty hits when we don't have results", () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = []; - - expect(actual.hits).toEqual(expectation); - }); - }); - - describe('position', () => { - it('expect to return the position from the searchState (aroundLatLng)', () => { - const props = { contextValue }; - const searchResults = createSingleIndexSearchResults(); - const searchState = { - aroundLatLng: { - lat: 10, - lng: 12, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to return the position from the searchState (configure.aroundLatLng)', () => { - const props = { contextValue }; - const searchResults = createSingleIndexSearchResults(); - const searchState = { - configure: { - aroundLatLng: '10, 12', - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to return the position from the SearchResults', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults([], { - aroundLatLng: '10, 12', - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to return undefined from an empty searchState', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toBe(undefined); - }); - - it('expect to return undefined with the default refinement', () => { - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - const props = { - contextValue, - defaultRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toBe(undefined); - }); - }); - - describe('currentRefinement', () => { - it('expect to return the boundingBox from the searchState', () => { - const props = { contextValue }; - const searchResults = createSingleIndexSearchResults(); - const searchState = { - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return the boundingBox from the searchState with string values', () => { - const props = { contextValue }; - const searchResults = createSingleIndexSearchResults(); - const searchState = { - boundingBox: { - northEast: { - lat: '10.12', - lng: 12.1, - }, - southWest: { - lat: 12.14, - lng: '14.12', - }, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10.12, - lng: 12.1, - }, - southWest: { - lat: 12.14, - lng: 14.12, - }, - }); - }); - - it('expect to return the boundingBox from the SearchResults', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults([], { - insideBoundingBox: '10, 12, 12, 14', - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return the default refinement', () => { - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - const props = { - contextValue, - defaultRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return undefined from an empty searchState', () => { - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(undefined); - }); - }); - - describe('isRefinedWithMap', () => { - it("expect to return true when it's refined with the map (from the searchState)", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue }; - const searchResults = createSingleIndexSearchResults(hits); - const searchState = { - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(true); - }); - - it("expect to return true when it's refined with the map (from the searchParameters)", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(hits, { - insideBoundingBox: '10, 12, 12, 14', - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(true); - }); - - it("expect to return false when it's not refined with the map", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(false); - }); - }); - }); - - describe('refine', () => { - it('expect to set the boundingBox when boundingBox is provided', () => { - const props = { contextValue }; - const searchState = {}; - const nextRefinement = { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }; - - const actual = connector.refine(props, searchState, nextRefinement); - - expect(actual).toEqual({ - page: 1, - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - }); - - it('expect to replace the previous value when boundingBox is provided', () => { - const props = { contextValue }; - const searchState = { - boundingBox: { - northEast: { - lat: 8, - lng: 10, - }, - southWest: { - lat: 10, - lng: 12, - }, - }, - }; - - const nextRefinement = { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }; - - const actual = connector.refine(props, searchState, nextRefinement); - - expect(actual).toEqual({ - page: 1, - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - }); - - it('expect to clear the previous value when boundingBox is omit', () => { - const props = { contextValue }; - const searchState = { - boundingBox: { - northEast: { - lat: 8, - lng: 10, - }, - southWest: { - lat: 10, - lng: 12, - }, - }, - }; - - const actual = connector.refine(props, searchState); - - const expectation = { - page: 1, - }; - - expect(actual).toEqual(expectation); - }); - }); - - describe('getSearchParameters', () => { - it('expect to set the parameter "insideBoundingBox" when boundingBox is provided', () => { - const searchParameters = new SearchParameters(); - const props = { contextValue }; - const searchState = { - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getSearchParameters( - searchParameters, - props, - searchState - ); - - const expectation = '10,12,12,14'; - - expect(actual.insideBoundingBox).toEqual(expectation); - }); - - it('expect to return the given searchParameters when boundingBox is omit', () => { - const searchParameters = new SearchParameters(); - const props = { contextValue }; - const searchState = {}; - - const actual = connector.getSearchParameters( - searchParameters, - props, - searchState - ); - - expect(actual).toEqual(searchParameters); - }); - }); - - describe('cleanUp', () => { - it('expect to remove the refinement from the searchState when boundingBox is provided', () => { - const props = { contextValue }; - const searchState = { - query: 'studio', - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.cleanUp(props, searchState); - - const expectation = { - query: 'studio', - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to return the given searchState when boundingBox is omit', () => { - const props = { contextValue }; - const searchState = { - query: 'studio', - }; - - const actual = connector.cleanUp(props, searchState); - - const expectation = { - query: 'studio', - }; - - expect(actual).toEqual(expectation); - }); - }); - - describe('getMetadata', () => { - it('expect to return the meta when boundingBox is provided', () => { - const props = { contextValue }; - const searchState = { - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const actual = connector.getMetadata(props, searchState); - - const expectation = { - id: 'boundingBox', - index: 'index', - items: [ - { - label: 'boundingBox: 10,12,12,14', - value: expect.any(Function), - currentRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }, - ], - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to return an empty meta when boundingBox is omit', () => { - const props = { contextValue }; - const searchState = {}; - - const actual = connector.getMetadata(props, searchState); - - expect(actual).toEqual({ - id: 'boundingBox', - index: 'index', - items: [], - }); - }); - - it('expect to clear the boundingBox when value is called', () => { - const props = { contextValue }; - const searchState = { - query: 'studio', - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const metadata = connector.getMetadata(props, searchState); - const actual = metadata.items[0].value(searchState); - - expect(actual).toEqual({ - query: 'studio', - boundingBox: {}, - page: 1, - }); - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - const createMultiIndexSearchState = (state = {}) => ({ - indices: { - second: state, - }, - }); - - const createMultiIndexSearchResults = (hits = [], state) => ({ - results: { - second: new SearchResults(new SearchParameters(state), [ - { - hits, - }, - ]), - }, - }); - - describe('getProvidedProps', () => { - it('expect to return default provided props', () => { - const searchState = createMultiIndexSearchState(); - const props = { contextValue, indexContextValue }; - - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = { - hits: [], - position: undefined, - currentRefinement: undefined, - isRefinedWithMap: false, - }; - - expect(actual).toEqual(expectation); - }); - - describe('hits', () => { - it('expect to return hits when we have results', () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - expect(actual.hits).toEqual(expectation); - }); - - it('expect to return hits with only "_geoloc" when we have results', () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: false }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = [ - { objectID: '123', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - expect(actual.hits).toEqual(expectation); - }); - - it("expect to return empty hits when we don't have results", () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = empty; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - const expectation = []; - - expect(actual.hits).toEqual(expectation); - }); - }); - - describe('position', () => { - it('expect to return the position from the searchState (aroundLatLng)', () => { - const props = { contextValue, indexContextValue }; - const searchResults = createMultiIndexSearchResults(); - const searchState = createMultiIndexSearchState({ - aroundLatLng: { - lat: 10, - lng: 12, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to return the position from the searchState (configure.aroungLatLng)', () => { - const props = { contextValue, indexContextValue }; - const searchResults = createMultiIndexSearchResults(); - const searchState = createMultiIndexSearchState({ - configure: { - aroundLatLng: '10, 12', - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to return undefined from an empty searchState', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toBe(undefined); - }); - - it('expect to return undefined with the default refinement', () => { - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - const props = { - defaultRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - contextValue, - indexContextValue, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.position).toBe(undefined); - }); - }); - - describe('currentRefinement', () => { - it('expect to return the boundingBox from the searchState', () => { - const props = { contextValue, indexContextValue }; - const searchResults = createMultiIndexSearchResults(); - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return the boundingBox from the searchState with string values', () => { - const props = { contextValue, indexContextValue }; - const searchResults = createMultiIndexSearchResults(); - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: '10.12', - lng: 12.1, - }, - southWest: { - lat: 12.14, - lng: '14.12', - }, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10.12, - lng: 12.1, - }, - southWest: { - lat: 12.14, - lng: 14.12, - }, - }); - }); - - it('expect to return the boundingBox from the SearchResults', () => { - const props = { contextValue, indexContextValue }; - const searchState = {}; - const searchResults = createMultiIndexSearchResults([], { - insideBoundingBox: '10, 12, 12, 14', - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return the default refinement', () => { - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - const props = { - defaultRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - contextValue, - indexContextValue, - }; - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to return an undefined from an empty searchState', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(undefined); - }); - }); - - describe('isRefinedWithMap', () => { - it("expect to return true when it's refined with the map (from the searchState)", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue, indexContextValue }; - const searchResults = createMultiIndexSearchResults(hits); - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(true); - }); - - it("expect to return true when it's refined with the map (from the searchParameters)", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(hits, { - insideBoundingBox: '10, 12, 12, 14', - }); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(true); - }); - - it("expect to return false when it's not refined with the map", () => { - const hits = [ - { objectID: '123', _geoloc: true }, - { objectID: '456', _geoloc: true }, - { objectID: '789', _geoloc: true }, - ]; - - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults(hits); - - const actual = connector.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.isRefinedWithMap).toBe(false); - }); - }); - }); - - describe('refine', () => { - it('expect to set the boundingBox when boundingBox is provided', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - const nextRefinement = { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }; - - const actual = connector.refine(props, searchState, nextRefinement); - - const expectation = { - indices: { - second: { - page: 1, - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to replace the previous value when boundingBox is provided', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 8, - lng: 10, - }, - southWest: { - lat: 10, - lng: 12, - }, - }, - }); - - const nextRefinement = { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }; - - const actual = connector.refine(props, searchState, nextRefinement); - - const expectation = { - indices: { - second: { - page: 1, - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to clear the previous value when boundingBox is omit', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 8, - lng: 10, - }, - southWest: { - lat: 10, - lng: 12, - }, - }, - }); - - const actual = connector.refine(props, searchState); - - const expectation = { - indices: { - second: { - page: 1, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - }); - - describe('getSearchParameters', () => { - it('expect to set the parameter "insideBoundingBox" when boundingBox is provided', () => { - const searchParameters = new SearchParameters(); - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const actual = connector.getSearchParameters( - searchParameters, - props, - searchState - ); - - const expectation = '10,12,12,14'; - - expect(actual.insideBoundingBox).toEqual(expectation); - }); - - it('expect to return the given searchParameters when boundingBox is omit', () => { - const searchParameters = new SearchParameters(); - const props = { contextValue, indexContextValue }; - const searchState = {}; - - const actual = connector.getSearchParameters( - searchParameters, - props, - searchState - ); - - expect(actual).toEqual(searchParameters); - }); - }); - - describe('cleanUp', () => { - it('expect to remove the refinement from the searchState when boundingBox is provided', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - query: 'studio', - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const actual = connector.cleanUp(props, searchState); - - const expectation = { - indices: { - second: { - query: 'studio', - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to return the given searchState when boundingBox is omit', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - query: 'studio', - }); - - const actual = connector.cleanUp(props, searchState); - - const expectation = { - indices: { - second: { - query: 'studio', - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - }); - - describe('getMetadata', () => { - it('expect to return the meta when boundingBox is provided', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const actual = connector.getMetadata(props, searchState); - - const expectation = { - id: 'boundingBox', - index: 'second', - items: [ - { - label: 'boundingBox: 10,12,12,14', - value: expect.any(Function), - currentRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }, - ], - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to return an empty meta when boundingBox is omit', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState(); - - const actual = connector.getMetadata(props, searchState); - - const expectation = { - id: 'boundingBox', - index: 'second', - items: [], - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to clear the boundingBox when value is called', () => { - const props = { contextValue, indexContextValue }; - const searchState = createMultiIndexSearchState({ - query: 'studio', - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }); - - const metadata = connector.getMetadata(props, searchState); - - const actual = metadata.items[0].value(searchState); - - const expectation = { - indices: { - second: { - query: 'studio', - boundingBox: {}, - page: 1, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - }); - }); - - describe('shouldComponentUpdate', () => { - it('expect to always return true', () => { - const expectation = true; - const actual = connector.shouldComponentUpdate(); - - expect(actual).toBe(expectation); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectHierarchicalMenu.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectHierarchicalMenu.js deleted file mode 100644 index 45f9a1ffa2..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectHierarchicalMenu.js +++ /dev/null @@ -1,1123 +0,0 @@ -import { SearchResults, SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectHierarchicalMenu'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectHierarchicalMenu', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - const results = { - getFacetValues: jest.fn(), - getFacetByName: () => true, - hits: [], - }; - - results.getFacetValues.mockImplementationOnce(() => ({})); - let props = connect.getProvidedProps( - { attributes: ['ok'], contextValue }, - { hierarchicalMenu: { ok: 'wat' } }, - { results } - ); - - expect(props).toEqual({ - canRefine: false, - currentRefinement: 'wat', - items: [], - }); - - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue }, - {}, - {} - ); - expect(props).toEqual({ - canRefine: false, - currentRefinement: null, - items: [], - }); - - results.getFacetValues.mockClear(); - results.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - count: 10, - }, - ], - })); - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 5, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - - props = connect.getProvidedProps( - { attributes: ['ok'], limit: 1, contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - ], - }, - ]); - - props = connect.getProvidedProps( - { - attributes: ['ok'], - showMore: true, - limit: 0, - showMoreLimit: 1, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - ], - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 5, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('facetValues results uses facetOrdering by default', () => { - const props = { - ...connect.defaultProps, - attributes: ['lvl0', 'lvl1'], - contextValue, - }; - const searchState = { hierarchicalMenu: { lvl0: 'wat' } }; - const state = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - const results = new SearchResults(state, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - lvl0: { - order: ['wat'], - }, - lvl1: { - order: ['wat > wut'], - }, - }, - }, - }, - facets: { - lvl0: { - wat: 20, - oy: 10, - }, - lvl1: { - 'wat > wot': 15, - 'wat > wut': 5, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(props, searchState, { - results, - }); - expect(providedProps.items).toEqual([ - { - label: 'wat', - value: undefined, - count: 20, - isRefined: true, - items: [ - { - label: 'wut', - value: 'wat > wut', - count: 5, - isRefined: false, - items: null, - }, - { - label: 'wot', - value: 'wat > wot', - count: 15, - isRefined: false, - items: null, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - isRefined: false, - items: null, - }, - ]); - }); - - it('facetValues results does not use facetOrdering if disabled', () => { - const props = { - attributes: ['lvl0', 'lvl1'], - facetOrdering: false, - contextValue, - }; - const searchState = { hierarchicalMenu: { lvl0: 'wat' } }; - const state = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - const results = new SearchResults(state, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - lvl0: { - order: ['wat'], - }, - lvl1: { - order: ['wat > wut'], - }, - }, - }, - }, - facets: { - lvl0: { - wat: 20, - oy: 10, - }, - lvl1: { - 'wat > wot': 15, - 'wat > wut': 5, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(props, searchState, { - results, - }); - expect(providedProps.items).toEqual([ - { - label: 'oy', - value: 'oy', - count: 10, - isRefined: false, - items: null, - }, - { - label: 'wat', - value: undefined, - count: 20, - isRefined: true, - items: [ - // default ordering: alphabetical - { - label: 'wot', - value: 'wat > wot', - count: 15, - isRefined: false, - items: null, - }, - { - label: 'wut', - value: 'wat > wut', - count: 5, - isRefined: false, - items: null, - }, - ], - }, - ]); - }); - - it('shows the effect of showMoreLimit when there is no transformItems', () => { - const results = { - getFacetValues: jest.fn(), - getFacetByName: () => true, - hits: [], - }; - results.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - count: 3, - }, - { - name: 'wit', - path: 'wat > wit', - escapedValue: 'wat > wit', - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - count: 10, - }, - { - name: 'ay', - path: 'ay', - escapedValue: 'ay', - count: 3, - }, - ], - })); - - const props = connect.getProvidedProps( - { - attributes: ['ok'], - showMore: true, - limit: 0, - showMoreLimit: 2, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 3, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - }); - - it('applies limit after transforming items', () => { - const results = { - getFacetValues: jest.fn(), - getFacetByName: () => true, - hits: [], - }; - results.getFacetValues.mockClear(); - results.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - count: 3, - }, - { - name: 'wit', - path: 'wat > wit', - escapedValue: 'wat > wit', - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - count: 10, - }, - { - name: 'ay', - path: 'ay', - escapedValue: 'ay', - count: 3, - }, - ], - })); - let props = connect.getProvidedProps( - { - attributes: ['ok'], - showMore: true, - limit: 0, - showMoreLimit: 3, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 3, - }, - { - label: 'wit', - value: 'wat > wit', - count: 5, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - { - label: 'ay', - value: 'ay', - count: 3, - }, - ]); - - function compareItem(a, b) { - if (a.label < b.label) return -1; - if (a.label > b.label) return 1; - return 0; - } - const transformItems = jest.fn((items) => items.sort(compareItem)); - props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - label: 'ay', - value: 'ay', - count: 3, - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 3, - }, - { - label: 'wit', - value: 'wat > wit', - count: 5, - }, - ], - }, - ]); - props = connect.getProvidedProps( - { - attributes: ['ok'], - transformItems, - showMore: true, - limit: 0, - showMoreLimit: 2, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'ay', - value: 'ay', - count: 3, - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { attributes: ['ok'], contextValue }, - { otherKey: 'val', hierarchicalMenu: { otherKey: 'val' } }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }); - }); - - it("increases maxValuesPerFacet when it isn't big enough", () => { - const initSP = new SearchParameters({ maxValuesPerFacet: 100 }); - - let params = connect.getSearchParameters( - initSP, - { - attributes: ['attribute'], - limit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - attributes: ['attribute'], - showMore: true, - showMoreLimit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - attributes: ['attribute'], - limit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - - params = connect.getSearchParameters( - initSP, - { - attributes: ['attribute'], - showMore: true, - showMoreLimit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - const params = connect.getSearchParameters( - initSP, - { - attributes: ['ATTRIBUTE'], - separator: 'SEPARATOR', - rootPath: 'ROOT_PATH', - showParentLevel: true, - limit: 1, - contextValue, - }, - { hierarchicalMenu: { ATTRIBUTE: 'ok' } } - ); - expect(params).toEqual( - initSP - .addHierarchicalFacet({ - name: 'ATTRIBUTE', - attributes: ['ATTRIBUTE'], - separator: 'SEPARATOR', - rootPath: 'ROOT_PATH', - showParentLevel: true, - }) - .toggleHierarchicalFacetRefinement('ATTRIBUTE', 'ok') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - describe('getMetaData', () => { - it('registers its id in metadata', () => { - const metadata = connect.getMetadata( - { attributes: ['ok'], contextValue }, - {} - ); - expect(metadata).toEqual({ items: [], index: 'index', id: 'ok' }); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attributes: ['ok'], contextValue }, - { hierarchicalMenu: { ok: 'wat' } } - ); - expect(metadata).toEqual({ - id: 'ok', - index: 'index', - items: [ - { - label: 'ok: wat', - attribute: 'ok', - currentRefinement: 'wat', - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - }); - - it('registers escaped filter in metadata', () => { - const metadata = connect.getMetadata( - { attributes: ['ok'], contextValue }, - { hierarchicalMenu: { ok: '\\-wat' } } - ); - expect(metadata).toEqual({ - id: 'ok', - index: 'index', - items: [ - { - label: 'ok: -wat', - attribute: 'ok', - currentRefinement: '\\-wat', - value: metadata.items[0].value, - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attributes: ['one'], contextValue }, - { hierarchicalMenu: { one: 'one', two: 'two' } } - ); - - const searchState = metadata.items[0].value({ - hierarchicalMenu: { one: 'one', two: 'two' }, - }); - - expect(searchState).toEqual({ - page: 1, - hierarchicalMenu: { one: '', two: 'two' }, - }); - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attributes: ['name'], contextValue }, - { - hierarchicalMenu: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - hierarchicalMenu: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attributes: ['name2'], contextValue }, - searchState - ); - expect(searchState).toEqual({ - another: { searchState: 'searchState' }, - hierarchicalMenu: {}, - }); - }); - - it('computes canRefine based on the length of the transformed items list', () => { - const transformItems = () => []; - const results = { - getFacetValues: () => ({ data: [{ id: 'test' }] }), - getFacetByName: () => true, - hits: [], - }; - - const props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue }, - {}, - { results } - ); - - expect(props.canRefine).toEqual(false); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - const results = { - second: { - getFacetValues: jest.fn(), - getFacetByName: () => true, - }, - }; - - results.second.getFacetValues.mockImplementationOnce(() => ({})); - let props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - { indices: { second: { hierarchicalMenu: { ok: 'wat' } } } }, - { results } - ); - expect(props).toEqual({ - canRefine: false, - currentRefinement: 'wat', - items: [], - }); - - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - {}, - {} - ); - expect(props).toEqual({ - canRefine: false, - currentRefinement: null, - items: [], - }); - - results.second.getFacetValues.mockClear(); - results.second.getFacetValues.mockImplementation(() => ({ - data: [ - { - name: 'wat', - path: 'wat', - escapedValue: 'wat', - count: 20, - data: [ - { - name: 'wot', - path: 'wat > wot', - escapedValue: 'wat > wot', - count: 15, - }, - { - name: 'wut', - path: 'wat > wut', - escapedValue: 'wat > wut', - count: 5, - }, - ], - }, - { - name: 'oy', - path: 'oy', - escapedValue: 'oy', - count: 10, - }, - ], - })); - props = connect.getProvidedProps( - { attributes: ['ok'], contextValue, indexContextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 5, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - - props = connect.getProvidedProps( - { attributes: ['ok'], limit: 1, contextValue, indexContextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - ], - }, - ]); - - props = connect.getProvidedProps( - { - attributes: ['ok'], - showMore: true, - limit: 0, - showMoreLimit: 1, - contextValue, - indexContextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - ], - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attributes: ['ok'], transformItems, contextValue, indexContextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - label: 'wat', - value: 'wat', - count: 20, - items: [ - { - label: 'wot', - value: 'wat > wot', - count: 15, - }, - { - label: 'wut', - value: 'wat > wut', - count: 5, - }, - ], - }, - { - label: 'oy', - value: 'oy', - count: 10, - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { attributes: ['ok'], contextValue, indexContextValue }, - { - indices: { - first: { otherKey: 'val1', hierarchicalMenu: { otherKey: 'val1' } }, - second: { otherKey: 'val', hierarchicalMenu: { otherKey: 'val' } }, - }, - }, - 'yep' - ); - - expect(nextState).toEqual({ - indices: { - first: { - otherKey: 'val1', - hierarchicalMenu: { otherKey: 'val1' }, - }, - second: { - otherKey: 'val', - page: 1, - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - - nextState = connect.refine( - { - attributes: ['ok'], - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'second' }, - }, - { - indices: { - first: { - otherKey: 'val', - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }, - 'yep' - ); - - expect(nextState).toEqual({ - indices: { - first: { - otherKey: 'val', - hierarchicalMenu: { ok: 'yep', otherKey: 'val' }, - }, - second: { page: 1, hierarchicalMenu: { ok: 'yep' } }, - }, - }); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - const params = connect.getSearchParameters( - initSP, - { - attributes: ['ATTRIBUTE'], - separator: 'SEPARATOR', - rootPath: 'ROOT_PATH', - showParentLevel: true, - limit: 1, - contextValue, - indexContextValue, - }, - { - indices: { - second: { otherKey: 'val', hierarchicalMenu: { ATTRIBUTE: 'ok' } }, - }, - } - ); - expect(params).toEqual( - initSP - .addHierarchicalFacet({ - name: 'ATTRIBUTE', - attributes: ['ATTRIBUTE'], - separator: 'SEPARATOR', - rootPath: 'ROOT_PATH', - showParentLevel: true, - }) - .toggleHierarchicalFacetRefinement('ATTRIBUTE', 'ok') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attributes: ['ok'], contextValue, indexContextValue }, - { indices: { second: { hierarchicalMenu: { ok: 'wat' } } } } - ); - expect(metadata).toEqual({ - id: 'ok', - index: 'second', - items: [ - { - label: 'ok: wat', - attribute: 'ok', - currentRefinement: 'wat', - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attributes: ['one'], contextValue, indexContextValue }, - { - indices: { second: { hierarchicalMenu: { one: 'one', two: 'two' } } }, - } - ); - - const searchState = metadata.items[0].value({ - indices: { second: { hierarchicalMenu: { one: 'one', two: 'two' } } }, - }); - - expect(searchState).toEqual({ - indices: { - second: { page: 1, hierarchicalMenu: { one: '', two: 'two' } }, - }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attributes: ['one'], contextValue, indexContextValue }, - { - indices: { - second: { - hierarchicalMenu: { one: 'one', two: 'two' }, - another: { searchState: 'searchState' }, - }, - }, - } - ); - expect(searchState).toEqual({ - indices: { - second: { - hierarchicalMenu: { two: 'two' }, - another: { searchState: 'searchState' }, - }, - }, - }); - - searchState = connect.cleanUp( - { attributes: ['two'], contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - indices: { - second: { - another: { searchState: 'searchState' }, - hierarchicalMenu: {}, - }, - }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectHitInsights.ts b/packages/react-instantsearch-core/src/connectors/__tests__/connectHitInsights.ts deleted file mode 100644 index d4e35e26b5..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectHitInsights.ts +++ /dev/null @@ -1,140 +0,0 @@ -import connectReal from '../connectHitInsights'; - -jest.mock('../../core/createConnector', () => (x: any) => x); -// our mock implementation is diverging from the regular createConnector, -// so we redefine it as `any` here, since we have no more information -// @TODO: refactor these tests to work better with TS -const connect: (client: any) => any = connectReal; - -function setup() { - const insightsClient = jest.fn(); - - const contextValue = { - mainTargetedIndex: 'firstIndex', - }; - const indexContextValue = { - targetedIndex: 'theIndex', - }; - - const hit = { - objectID: 'objectID_42', - __position: 42, - __queryID: 'theQueryID', - }; - const searchResults = { results: { theIndex: { index: 'theIndex' } } }; - const props = connect(insightsClient).getProvidedProps( - { hit, contextValue, indexContextValue }, - null, - searchResults - ); - return { insightsClient, props }; -} - -describe('connectHitInsights', () => { - it('should expose an `insights` property', () => { - const { props } = setup(); - expect(props).toHaveProperty('insights'); - }); - - it('exposed `insights` should be a function', () => { - const { props } = setup(); - expect(typeof props.insights).toBe('function'); - }); - - describe('when called with `clickedObjectIDsAfterSearch`', () => { - let insightsClient: jest.Mock; - beforeEach(() => { - const { insightsClient: aa, props } = setup(); - insightsClient = aa; - props.insights('clickedObjectIDsAfterSearch', { - eventName: 'Add to cart', - }); - }); - - it('should forward call to insightsClient with the correct payload', () => { - expect(insightsClient).toHaveBeenCalledTimes(1); - const [method, payload] = insightsClient.mock.calls[0]; - expect(method).toEqual('clickedObjectIDsAfterSearch'); - expect(payload).toEqual({ - eventName: 'Add to cart', - objectIDs: ['objectID_42'], - positions: [42], - queryID: 'theQueryID', - index: 'theIndex', - }); - }); - }); - - describe('when called with `convertedObjectIDsAfterSearch`', () => { - let insightsClient: jest.Mock; - beforeEach(() => { - const { insightsClient: aa, props } = setup(); - insightsClient = aa; - props.insights('convertedObjectIDsAfterSearch', { - eventName: 'Add to cart', - }); - }); - - it('should forward call to insightsClient with the correct payload', () => { - expect(insightsClient).toHaveBeenCalledTimes(1); - - const [method, payload] = insightsClient.mock.calls[0]; - expect(method).toEqual('convertedObjectIDsAfterSearch'); - expect(payload).toEqual({ - eventName: 'Add to cart', - objectIDs: ['objectID_42'], - queryID: 'theQueryID', - index: 'theIndex', - }); - }); - }); - - describe('when called with an unsupported method', () => { - it('should reject the call', () => { - expect(() => { - const { props } = setup(); - // @ts-ignore - props.insights('wrong-method-name', { - eventName: 'Add to cart', - }); - }).toThrowErrorMatchingInlineSnapshot( - `"Unsupported method \\"wrong-method-name\\" passed to the insights function. The supported methods are: \\"clickedObjectIDsAfterSearch\\", \\"convertedObjectIDsAfterSearch\\"."` - ); - }); - }); - - describe('when queryID is undefined', () => { - it('should throw an error message inviting to add clickAnalytics: true', () => { - const insightsClient = jest.fn(); - - const contextValue = { - mainTargetedIndex: 'firstIndex', - }; - const indexContextValue = { - targetedIndex: 'theIndex', - }; - - const hit = { - objectID: 'objectID_42', - __position: 42, - // no queryID - }; - - const searchResults = { results: { theIndex: { index: 'theIndex' } } }; - const props = connect(insightsClient).getProvidedProps( - { hit, contextValue, indexContextValue }, - null, - searchResults - ); - - expect(() => { - props.insights('clickedObjectIDsAfterSearch', { - eventName: 'Add to wishlist', - }); - }).toThrowErrorMatchingInlineSnapshot(` -"Could not infer \`queryID\`. Ensure \`clickAnalytics: true\` was added with the Configure widget. -See: https://alg.li/VpPpLt" -`); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectHits.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectHits.js deleted file mode 100644 index ddeadb638d..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectHits.js +++ /dev/null @@ -1,116 +0,0 @@ -import connect from '../connectHits'; - -jest.mock('../../core/createConnector', () => (x) => x); - -const { getSearchParameters } = connect; - -describe('connectHits', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the current hits to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps({ contextValue }, null, { - results: { hits, hitsPerPage: 2, page: 2 }, - }); - expect(props).toEqual({ - hits: hits.map((hit) => expect.objectContaining(hit)), - }); - }); - - it('adds positions to the hits provided to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps({ contextValue }, null, { - results: { hits, hitsPerPage: 2, page: 2 }, - }); - expect(props).toEqual({ - hits: [{ __position: 5 }], - }); - }); - - it('adds queryID to the hits provided to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps({ contextValue }, null, { - results: { hits, hitsPerPage: 2, page: 2, queryID: 'theQueryID' }, - }); - expect(props).toEqual({ - hits: [expect.objectContaining({ __queryID: 'theQueryID' })], - }); - }); - - it("doesn't render when no hits are available", () => { - const props = connect.getProvidedProps({ contextValue }, null, { - results: null, - }); - expect(props).toEqual({ hits: [] }); - }); - - it('should return the searchParameters unchanged', () => { - const searchParameters = getSearchParameters({ hitsPerPage: 10 }); - expect(searchParameters).toEqual({ hitsPerPage: 10 }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the current hits to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, hitsPerPage: 2, page: 2 } }, - } - ); - expect(props).toEqual({ - hits: hits.map((hit) => expect.objectContaining(hit)), - }); - }); - - it('adds positions to the hits provided to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, hitsPerPage: 2, page: 2 } }, - } - ); - expect(props).toEqual({ - hits: [{ __position: 5 }], - }); - }); - - it('adds queryID to the hits provided to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits, hitsPerPage: 2, page: 2, queryID: 'theQueryID' }, - }, - } - ); - expect(props).toEqual({ - hits: [expect.objectContaining({ __queryID: 'theQueryID' })], - }); - }); - - it("doesn't render when no hits are available", () => { - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { results: { second: null } } - ); - expect(props).toEqual({ hits: [] }); - }); - - it('should return the searchParameters unchanged', () => { - const searchParameters = getSearchParameters({ hitsPerPage: 10 }); - expect(searchParameters).toEqual({ hitsPerPage: 10 }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectHitsPerPage.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectHitsPerPage.js deleted file mode 100644 index cbd558758a..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectHitsPerPage.js +++ /dev/null @@ -1,246 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectHitsPerPage'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectHitsPerPage', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - const items = [ - { label: '10', value: 10 }, - { label: '20', value: 20 }, - ]; - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { items, contextValue }, - { hitsPerPage: '10' } - ); - expect(props).toEqual({ - currentRefinement: 10, - items: [ - { label: '10', value: 10, isRefined: true }, - { - label: '20', - value: 20, - isRefined: false, - }, - ], - }); - - props = connect.getProvidedProps( - { defaultRefinement: 20, items, contextValue }, - {} - ); - expect(props).toEqual({ - currentRefinement: 20, - items: [ - { - label: '10', - value: 10, - isRefined: false, - }, - { label: '20', value: 20, isRefined: true }, - ], - }); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { items, transformItems, contextValue }, - { hitsPerPage: '10' } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { label: '10', value: 10, isRefined: true }, - { label: '20', value: 20, isRefined: false }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue }, - { otherKey: 'val' }, - 30 - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - hitsPerPage: 30, - }); - }); - - it('refines the hitsPerPage parameter', () => { - const sp = new SearchParameters(); - - params = connect.getSearchParameters( - sp, - { contextValue }, - { hitsPerPage: 10 } - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 10)); - - params = connect.getSearchParameters( - sp, - { contextValue }, - { hitsPerPage: '10' } - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 10)); - - params = connect.getSearchParameters( - sp, - { defaultRefinement: 20, contextValue }, - {} - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 20)); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata({ contextValue }); - expect(metadata).toEqual({ id: 'hitsPerPage' }); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue }, - { - hitsPerPage: 'searchState', - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ another: { searchState: 'searchState' } }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - const items = [ - { label: '10', value: 10 }, - { label: '20', value: 20 }, - ]; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { items, contextValue, indexContextValue }, - { indices: { second: { hitsPerPage: '10' } } } - ); - expect(props).toEqual({ - currentRefinement: 10, - items: [ - { label: '10', value: 10, isRefined: true }, - { - label: '20', - value: 20, - isRefined: false, - }, - ], - }); - - props = connect.getProvidedProps( - { defaultRefinement: 20, items, contextValue, indexContextValue }, - {} - ); - expect(props).toEqual({ - currentRefinement: 20, - items: [ - { - label: '10', - value: 10, - isRefined: false, - }, - { label: '20', value: 20, isRefined: true }, - ], - }); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { items, transformItems, contextValue, indexContextValue }, - { indices: { second: { hitsPerPage: '10' } } } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { label: '10', value: 10, isRefined: true }, - { label: '20', value: 20, isRefined: false }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { contextValue, indexContextValue }, - { indices: { second: { otherKey: 'val' } } }, - 30 - ); - expect(nextState).toEqual({ - indices: { - second: { page: 1, otherKey: 'val', hitsPerPage: 30 }, - }, - }); - - nextState = connect.refine( - { - contextValue: { mainTargetedIndex: 'second' }, - indexContextValue: { targetedIndex: 'second' }, - }, - { indices: { second: { otherKey: 'val', hitsPerPage: 30 } } }, - 30 - ); - expect(nextState).toEqual({ - indices: { - second: { otherKey: 'val', hitsPerPage: 30, page: 1 }, - }, - }); - }); - - it('correctly applies its state to search parameters', () => { - const sp = new SearchParameters(); - - params = connect.getSearchParameters( - sp, - { contextValue, indexContextValue }, - { indices: { second: { hitsPerPage: '10' } } } - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 10)); - - params = connect.getSearchParameters( - sp, - { contextValue, indexContextValue }, - { indices: { second: { hitsPerPage: '10' } } } - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 10)); - - params = connect.getSearchParameters( - sp, - { defaultRefinement: 20, contextValue, indexContextValue }, - {} - ); - expect(params).toEqual(sp.setQueryParameter('hitsPerPage', 20)); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata({}); - expect(metadata).toEqual({ id: 'hitsPerPage' }); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue, indexContextValue }, - { - indices: { - second: { - hitsPerPage: 'searchState', - another: { searchState: 'searchState' }, - }, - }, - } - ); - expect(searchState).toEqual({ - indices: { second: { another: { searchState: 'searchState' } } }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectInfiniteHits.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectInfiniteHits.js deleted file mode 100644 index 0fb58a0643..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectInfiniteHits.js +++ /dev/null @@ -1,1059 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import isEqual from 'react-fast-compare'; - -import connect from '../connectInfiniteHits'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectInfiniteHits', () => { - describe('single index', () => { - const contextValue = { - mainTargetedIndex: 'index', - }; - - it('provides the current hits to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps.call({}, { contextValue }, null, { - results: { hits, page: 0, hitsPerPage: 2, nbPages: 3 }, - }); - - expect(props).toEqual({ - hits: hits.map((hit) => expect.objectContaining(hit)), - hasPrevious: false, - hasMore: true, - refinePrevious: expect.any(Function), - refineNext: expect.any(Function), - }); - }); - - it('accumulate hits internally', () => { - const hits = [{}, {}]; - const hits2 = [{}, {}]; - const instance = {}; - - const res1 = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { hits, page: 0, hitsPerPage: 2, nbPages: 3 }, - } - ); - - expect(res1.hits).toEqual( - hits.map((hit) => expect.objectContaining(hit)) - ); - expect(res1.hasMore).toBe(true); - - const res2 = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: hits2, - page: 1, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - expect(res2.hits).toEqual( - [...hits, ...hits2].map((hit) => expect.objectContaining(hit)) - ); - expect(res2.hasMore).toBe(true); - }); - - it('prepend hits internally', () => { - const instance = {}; - const initialPageHits = [{}, {}]; - const previousPageHits = [{}, {}]; - const initialPageProps = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: initialPageHits, - page: 1, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - expect(initialPageProps.hits).toEqual( - initialPageHits.map((hit) => expect.objectContaining(hit)) - ); - expect(initialPageProps.hasPrevious).toBe(true); - - const previousPageProps = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: previousPageHits, - page: 0, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - expect(previousPageProps.hits).toEqual( - [...previousPageHits, ...initialPageHits].map((hit) => - expect.objectContaining(hit) - ) - ); - expect(previousPageProps.hasPrevious).toBe(false); - }); - - it('accumulate hits internally while changing hitsPerPage configuration', () => { - const hits = [{}, {}, {}, {}, {}, {}]; - const hits2 = [{}, {}, {}, {}, {}, {}]; - const hits3 = [{}, {}, {}, {}, {}, {}, {}, {}]; - const instance = {}; - - const res1 = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits, - page: 0, - hitsPerPage: 6, - nbPages: 10, - queryID: 'theQueryID_0', - }, - } - ); - - expect(res1.hits).toEqual( - hits.map((hit) => expect.objectContaining(hit)) - ); - expect(res1.hits.map((hit) => hit.__position)).toEqual([ - 1, 2, 3, 4, 5, 6, - ]); - expect(res1.hits.map((hit) => hit.__queryID)).toEqual([ - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - ]); - expect(res1.hasMore).toBe(true); - - const res2 = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: hits2, - page: 1, - hitsPerPage: 6, - nbPages: 10, - queryID: 'theQueryID_1', - }, - } - ); - - expect(res2.hits).toEqual( - [...hits, ...hits2].map((hit) => expect.objectContaining(hit)) - ); - expect(res2.hits.map((hit) => hit.__position)).toEqual([ - // page 0 - 1, 2, 3, 4, 5, 6, - // page 1 - 7, 8, 9, 10, 11, 12, - ]); - expect(res2.hits.map((hit) => hit.__queryID)).toEqual([ - // page 0 - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - // page 1 - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - ]); - expect(res2.hasMore).toBe(true); - - let res3 = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: hits3, - page: 2, - hitsPerPage: 8, - nbPages: 10, - queryID: 'theQueryID_2', - }, - } - ); - - expect(res3.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(res3.hits.map((hit) => hit.__position)).toEqual([ - // page: 0, hitsPerPage: 6 - 1, 2, 3, 4, 5, 6, - // page: 1, hitsPerPage: 6 - 7, 8, 9, 10, 11, 12, - // hitsPerPage changed from 6 to 8, elements 13-16 are skipped - // page: 2, hitsPerPage: 8 - 17, 18, 19, 20, 21, 22, 23, 24, - ]); - expect(res3.hits.map((hit) => hit.__queryID)).toEqual([ - // page 0 - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - // page 1 - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - // page 2 - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_2', - ]); - expect(res3.hasMore).toBe(true); - - // re-render with the same property - res3 = connect.getProvidedProps.call(instance, { contextValue }, null, { - results: { - hits: hits3, - page: 2, - hitsPerPage: 8, - nbPages: 10, - queryID: 'theQueryID_2_', - }, - }); - - expect(res3.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(res3.hits.map((hit) => hit.__position)).toEqual([ - // page: 0, hitsPerPage: 6 - 1, 2, 3, 4, 5, 6, - // page: 1, hitsPerPage: 6 - 7, 8, 9, 10, 11, 12, - // hitsPerPage changed from 6 to 8, elements 13-16 are skipped - // page: 2, hitsPerPage: 8 - 17, 18, 19, 20, 21, 22, 23, 24, - ]); - expect(res3.hits.map((hit) => hit.__queryID)).toEqual([ - // page 0 - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_0', - // page 1 - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_1', - // page 2 - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - 'theQueryID_2_', - ]); - expect(res3.hasMore).toBe(true); - }); - - it('should not reset while accumulating results', () => { - const hits = [{}, {}]; - const nbPages = 5; - const instance = {}; - - let allHits = []; - for (let page = 0; page < nbPages - 1; page++) { - allHits = [...allHits, ...hits]; - - const res = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits, - page, - hitsPerPage: hits.length, - nbPages, - queryID: `theQueryID_${page}`, - }, - } - ); - - expect(res.hits).toEqual( - allHits.map((hit) => expect.objectContaining(hit)) - ); - expect(res.hits).toHaveLength((page + 1) * 2); - expect(res.hasMore).toBe(true); - } - - allHits = [...allHits, ...hits]; - - const res = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits, - page: nbPages - 1, - hitsPerPage: hits.length, - nbPages, - queryID: `theQueryID_${nbPages - 1}`, - }, - } - ); - - expect(res.hits).toHaveLength(nbPages * 2); - expect(res.hits).toEqual( - allHits.map((hit) => expect.objectContaining(hit)) - ); - expect(res.hits.map((hit) => hit.__position)).toEqual([ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - ]); - expect(res.hits.map((hit) => hit.__queryID)).toEqual([ - 'theQueryID_0', - 'theQueryID_0', - 'theQueryID_1', - 'theQueryID_1', - 'theQueryID_2', - 'theQueryID_2', - 'theQueryID_3', - 'theQueryID_3', - 'theQueryID_4', - 'theQueryID_4', - ]); - expect(res.hasMore).toBe(false); - }); - - it('Indicates the last page after several pages', () => { - const hits = [{}, {}]; - const hits2 = [{}, {}]; - const hits3 = [{}]; - const instance = {}; - - connect.getProvidedProps.call(instance, { contextValue }, null, { - results: { hits, page: 0, hitsPerPage: 2, nbPages: 3 }, - }); - - connect.getProvidedProps.call(instance, { contextValue }, null, { - results: { - hits: hits2, - page: 1, - hitsPerPage: 2, - nbPages: 3, - }, - }); - - const props = connect.getProvidedProps.call( - instance, - { contextValue }, - null, - { - results: { - hits: hits3, - page: 2, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - expect(props.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(props.hasMore).toBe(false); - }); - - it('calls refine with next page when calling refineNext', () => { - const instance = { refine: jest.fn() }; - const hits = [{}, {}]; - const event = new Event('click'); - - const props = connect.getProvidedProps.call( - instance, - { contextValue }, - {}, - { - results: { - hits, - page: 2, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - props.refineNext.call(instance, event); - - expect(instance.refine).toHaveBeenCalledTimes(1); - expect(instance.refine).toHaveBeenLastCalledWith(event, 3); - }); - - it('calls refine with previous page when calling refinePrevious', () => { - const instance = { refine: jest.fn() }; - const hits = [{}, {}]; - const event = new Event('click'); - - const props = connect.getProvidedProps.call( - instance, - { contextValue }, - {}, - { - results: { - hits, - page: 2, - hitsPerPage: 2, - nbPages: 3, - }, - } - ); - - props.refinePrevious.call(instance, event); - - expect(instance.refine).toHaveBeenCalledTimes(1); - expect(instance.refine).toHaveBeenLastCalledWith(event, 1); - }); - - it('set page to the corresponding index', () => { - const props = { contextValue }; - const state0 = {}; - const event = new Event('click'); - const index = 5; - - const state1 = connect.refine.call({}, props, state0, event, index); - // `index` is indexed from 0 but page number is indexed from 1 - expect(state1).toEqual({ page: 6 }); - }); - - it('expect to always return an array of hits', () => { - const props = { contextValue }; - const searchState = {}; - - // Retrieve the results from the cache that's why - // the page it's not zero on the first render - const searchResults = { - results: { - hits: [{}, {}, {}], - hitsPerPage: 3, - page: 1, - nbPages: 3, - }, - }; - - const expectation = { - hits: [{}, {}, {}].map((hit) => expect.objectContaining(hit)), - hasPrevious: true, - hasMore: true, - refinePrevious: expect.any(Function), - refineNext: expect.any(Function), - }; - - const actual = connect.getProvidedProps.call( - {}, - props, - searchState, - searchResults - ); - - expect(actual).toEqual(expectation); - }); - - it('does not read from given cache when results is empty', () => { - const cache = { - read: jest.fn(), - write: jest.fn(), - }; - const props = { cache, contextValue }; - const searchState = {}; - const searchResults = {}; - connect.getProvidedProps.call({}, props, searchState, searchResults); - expect(cache.read).toHaveBeenCalledTimes(0); - }); - - it('read from given cache', () => { - const cache = { - read: jest.fn(), - write: jest.fn(), - }; - const props = { cache, contextValue }; - const searchState = {}; - const searchResults = { - results: { - hits: [{}, {}, {}], - hitsPerPage: 3, - page: 1, - nbPages: 3, - }, - }; - connect.getProvidedProps.call({}, props, searchState, searchResults); - expect(cache.read).toHaveBeenCalledTimes(1); - }); - - it('read from new cache prop', () => { - const cache = { - read: jest.fn(), - write: jest.fn(), - }; - const searchState = {}; - const searchResults = { - results: { - hits: [{}, {}, {}], - hitsPerPage: 3, - page: 1, - nbPages: 3, - }, - }; - const instance = {}; - connect.getProvidedProps.call( - instance, - { cache, contextValue }, - searchState, - searchResults - ); - expect(cache.read).toHaveBeenCalledTimes(1); - - const cache2 = { - read: jest.fn(), - write: jest.fn(), - }; - connect.getProvidedProps.call( - instance, - { cache: cache2, contextValue }, - searchState, - searchResults - ); - expect(cache.read).toHaveBeenCalledTimes(1); - expect(cache2.read).toHaveBeenCalledTimes(1); - }); - - it('keep the same in-memory cache', () => { - const searchState = {}; - const searchResults = {}; - const instance = {}; - connect.getProvidedProps.call( - instance, - { contextValue }, - searchState, - searchResults - ); - const memoryCache = instance._cache; - - connect.getProvidedProps.call( - instance, - { contextValue }, - searchState, - searchResults - ); - expect(instance._cache).toBe(memoryCache); - }); - - it('render hits correctly after invalidating cache', () => { - const getStateWithoutPage = (state) => { - const { page, ...rest } = state || {}; - return rest; - }; - - const getInMemoryCache = () => { - let cachedHits = undefined; - let cachedState = undefined; - return { - read({ state }) { - return isEqual(cachedState, getStateWithoutPage(state)) - ? cachedHits - : null; - }, - write({ state, hits }) { - cachedState = getStateWithoutPage(state); - cachedHits = hits; - }, - clear() { - cachedHits = undefined; - cachedState = undefined; - }, - }; - }; - - const instance = {}; - const cache = getInMemoryCache(); - const props = { cache, contextValue }; - const searchState = {}; - const searchResults1 = { - results: { - hits: [{ objectID: 'a' }, { objectID: 'b' }, { objectID: 'c' }], - hitsPerPage: 3, - page: 0, - nbPages: 3, - }, - }; - expect( - connect.getProvidedProps.call( - instance, - props, - searchState, - searchResults1 - ).hits - ).toMatchInlineSnapshot(` - [ - { - "__position": 1, - "objectID": "a", - }, - { - "__position": 2, - "objectID": "b", - }, - { - "__position": 3, - "objectID": "c", - }, - ] - `); - - const searchResults2 = { - results: { - hits: [{ objectID: 'd' }, { objectID: 'e' }, { objectID: 'f' }], - hitsPerPage: 3, - page: 1, - nbPages: 3, - }, - }; - expect( - connect.getProvidedProps.call( - instance, - props, - searchState, - searchResults2 - ).hits - ).toMatchInlineSnapshot(` - [ - { - "__position": 1, - "objectID": "a", - }, - { - "__position": 2, - "objectID": "b", - }, - { - "__position": 3, - "objectID": "c", - }, - { - "__position": 4, - "objectID": "d", - }, - { - "__position": 5, - "objectID": "e", - }, - { - "__position": 6, - "objectID": "f", - }, - ] - `); - - cache.clear(); - expect( - connect.getProvidedProps.call( - instance, - props, - searchState, - searchResults2 - ).hits - ).toMatchInlineSnapshot(` - [ - { - "__position": 4, - "objectID": "d", - }, - { - "__position": 5, - "objectID": "e", - }, - { - "__position": 6, - "objectID": "f", - }, - ] - `); - }); - }); - - describe('multi index', () => { - const contextValue = { - mainTargetedIndex: 'first', - }; - const indexContextValue = { - targetedIndex: 'second', - }; - - it('provides the current hits to the component', () => { - const hits = [{}]; - const props = connect.getProvidedProps.call( - {}, - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, page: 0, hitsPerPage: 2, nbPages: 3 } }, - } - ); - - expect(props).toEqual({ - hits: hits.map((hit) => expect.objectContaining(hit)), - hasPrevious: false, - hasMore: true, - refinePrevious: expect.any(Function), - refineNext: expect.any(Function), - }); - }); - - it('accumulate hits internally', () => { - const hits = [{}, {}]; - const hits2 = [{}, {}]; - - const instance = {}; - - const res1 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, page: 0, hitsPerPage: 2, nbPages: 3 } }, - } - ); - - expect(res1.hits).toEqual( - hits.map((hit) => expect.objectContaining(hit)) - ); - expect(res1.hasMore).toBe(true); - - const res2 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits2, page: 1, hitsPerPage: 2, nbPages: 3 }, - }, - } - ); - - expect(res2.hits).toEqual( - [...hits, ...hits2].map((hit) => expect.objectContaining(hit)) - ); - expect(res2.hasMore).toBe(true); - }); - - it('prepend hits internally', () => { - const initialPageHits = [{}, {}]; - const previousPageHits = [{}, {}]; - const instance = {}; - const initialPageProps = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: initialPageHits, - page: 1, - hitsPerPage: 2, - nbPages: 3, - }, - }, - } - ); - - expect(initialPageProps.hits).toEqual( - initialPageHits.map((hit) => expect.objectContaining(hit)) - ); - expect(initialPageProps.hasPrevious).toBe(true); - - const previousPageProps = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: previousPageHits, - page: 0, - hitsPerPage: 2, - nbPages: 3, - }, - }, - } - ); - - expect(previousPageProps.hits).toEqual( - [...previousPageHits, ...initialPageHits].map((hit) => - expect.objectContaining(hit) - ) - ); - expect(previousPageProps.hasPrevious).toBe(false); - }); - - it('accumulate hits internally while changing hitsPerPage configuration', () => { - const hits = [{}, {}, {}, {}, {}, {}]; - const hits2 = [{}, {}, {}, {}, {}, {}]; - const hits3 = [{}, {}, {}, {}, {}, {}, {}, {}]; - const instance = {}; - - const res1 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, page: 0, hitsPerPage: 6, nbPages: 10 } }, - } - ); - - expect(res1.hits).toEqual( - hits.map((hit) => expect.objectContaining(hit)) - ); - expect(res1.hasMore).toBe(true); - - const res2 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits2, page: 1, hitsPerPage: 6, nbPages: 10 }, - }, - } - ); - - expect(res2.hits).toEqual( - [...hits, ...hits2].map((hit) => expect.objectContaining(hit)) - ); - expect(res2.hasMore).toBe(true); - - let res3 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits3, page: 2, hitsPerPage: 8, nbPages: 10 }, - }, - } - ); - - expect(res3.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(res3.hasMore).toBe(true); - - // re-render with the same property - res3 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits3, page: 2, hitsPerPage: 8, nbPages: 10 }, - }, - } - ); - - expect(res3.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(res3.hasMore).toBe(true); - }); - - it('should not accumulate hits internally while changing query', () => { - const instance = {}; - const hits = [{}, {}, {}, {}, {}, {}]; - const hits2 = [{}, {}, {}, {}, {}, {}]; - - const res1 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits, - page: 0, - hitsPerPage: 6, - nbPages: 10, - _state: { page: 0, query: 'a' }, - }, - }, - } - ); - - expect(res1.hits).toEqual( - hits.map((hit) => expect.objectContaining(hit)) - ); - expect(res1.hasMore).toBe(true); - - const res2 = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: hits2, - page: 0, - hitsPerPage: 6, - nbPages: 10, - _state: { page: 0, query: 'b' }, - }, - }, - } - ); - - expect(res2.hits).toEqual( - hits2.map((hit) => expect.objectContaining(hit)) - ); - expect(res2.hasMore).toBe(true); - }); - - it('should not reset while accumulating results', () => { - const hits = [{}, {}]; - const nbPages = 100; - const instance = {}; - - let allHits = []; - for (let page = 0; page < nbPages - 1; page++) { - allHits = [...allHits, ...hits]; - - const res = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits, - page, - hitsPerPage: hits.length, - nbPages, - }, - }, - } - ); - - expect(res.hits).toEqual( - allHits.map((hit) => expect.objectContaining(hit)) - ); - expect(res.hits).toHaveLength((page + 1) * 2); - expect(res.hasMore).toBe(true); - } - - allHits = [...allHits, ...hits]; - - const res = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits, - page: nbPages - 1, - hitsPerPage: hits.length, - nbPages, - }, - }, - } - ); - - expect(res.hits).toHaveLength(nbPages * 2); - expect(res.hits).toEqual( - allHits.map((hit) => expect.objectContaining(hit)) - ); - expect(res.hasMore).toBe(false); - }); - - it('Indicates the last page after several pages', () => { - const hits = [{}, {}]; - const hits2 = [{}, {}]; - const hits3 = [{}]; - const instance = {}; - - connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { second: { hits, page: 0, hitsPerPage: 2, nbPages: 3 } }, - } - ); - - connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits2, page: 1, hitsPerPage: 2, nbPages: 3 }, - }, - } - ); - - const props = connect.getProvidedProps.call( - instance, - { contextValue, indexContextValue }, - null, - { - results: { - second: { hits: hits3, page: 2, hitsPerPage: 2, nbPages: 3 }, - }, - } - ); - - expect(props.hits).toEqual( - [...hits, ...hits2, ...hits3].map((hit) => expect.objectContaining(hit)) - ); - expect(props.hasMore).toBe(false); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectMenu.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectMenu.js deleted file mode 100644 index eee944af54..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectMenu.js +++ /dev/null @@ -1,1087 +0,0 @@ -import { SearchParameters, SearchResults } from 'algoliasearch-helper'; - -import connect from '../connectMenu'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectMenu', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - const results = { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - hits: [], - }; - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - {} - ); - expect(props).toEqual({ - items: [], - currentRefinement: null, - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - { menu: { ok: 'wat' } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - { menu: { ok: 'wat' } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', defaultRefinement: 'wat', contextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: null, - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - results.getFacetValues.mockClear(); - results.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - escapedValue: 'wat', - isRefined: true, - count: 20, - }, - { - name: 'oy', - escapedValue: 'oy', - isRefined: false, - count: 10, - }, - ]); - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: 'oy', - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { - attribute: 'ok', - showMore: true, - limit: 0, - showMoreLimit: 1, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results }, - {}, - { - query: 'query', - ok: [ - { - value: 'wat', - escapedValue: 'wat', - count: 10, - highlighted: 'wat', - isRefined: false, - }, - ], - } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: false, - count: 10, - _highlightResult: { label: { value: 'wat' } }, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results }, - {}, - { query: '' } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attribute: 'ok', transformItems, contextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: 'oy', - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('if an item is equal to the currentRefinement, its value should be an empty string', () => { - const results = { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - hits: [], - }; - results.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - escapedValue: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - { menu: { ok: 'wat' } }, - { results } - ); - - expect(props.items).toEqual([ - { - value: '', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - }); - - it('facetValues have facetOrdering by default', () => { - const userProps = { - ...connect.defaultProps, - attribute: 'ok', - contextValue, - }; - const searchState = { - menu: { ok: 'wat' }, - }; - const parameters = connect.getSearchParameters( - new SearchParameters(), - userProps, - searchState - ); - - const searchResults = new SearchResults(parameters, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - ok: { - order: ['wat'], - }, - }, - }, - }, - facets: { - ok: { - wat: 20, - lol: 2000, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(userProps, searchState, { - results: searchResults, - }); - - expect(providedProps.items).toEqual([ - { - count: 20, - isRefined: true, - label: 'wat', - value: '', - }, - { - count: 2000, - isRefined: false, - label: 'lol', - value: 'lol', - }, - ]); - expect(providedProps.isFromSearch).toBe(false); - }); - - it('facetValues results does not use facetOrdering if disabled', () => { - const userProps = { attribute: 'ok', facetOrdering: false, contextValue }; - const searchState = { - menu: { ok: 'wat' }, - }; - const parameters = connect.getSearchParameters( - new SearchParameters(), - userProps, - searchState - ); - - const searchResults = new SearchResults(parameters, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - ok: { - order: ['wat'], - }, - }, - }, - }, - facets: { - ok: { - wat: 20, - lol: 2000, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(userProps, searchState, { - results: searchResults, - }); - - expect(providedProps.items).toEqual([ - { - count: 2000, - isRefined: false, - label: 'lol', - value: 'lol', - }, - { - count: 20, - isRefined: true, - label: 'wat', - value: '', - }, - ]); - expect(providedProps.isFromSearch).toBe(false); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { attribute: 'ok', contextValue }, - { otherKey: 'val', menu: { otherKey: 'val' } }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - menu: { ok: 'yep', otherKey: 'val' }, - }); - }); - - it("increases maxValuesPerFacet when it isn't big enough", () => { - const initSP = new SearchParameters({ maxValuesPerFacet: 100 }); - - params = connect.getSearchParameters( - initSP, - { - limit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - showMore: true, - showMoreLimit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - limit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - - params = connect.getSearchParameters( - initSP, - { - showMore: true, - showMoreLimit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - limit: 1, - contextValue, - }, - { menu: { ok: 'wat' } } - ); - expect(params).toEqual( - initSP - .addDisjunctiveFacet('ok') - .addDisjunctiveFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'ok', contextValue }, - {} - ); - expect(metadata).toEqual({ id: 'ok', index: 'index', items: [] }); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue }, - { menu: { wot: 'wat' } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: 'wot: wat', - attribute: 'wot', - currentRefinement: 'wat', - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', contextValue }, - { menu: { one: 'one', two: 'two' } } - ); - - const searchState = metadata.items[0].value({ - menu: { one: 'one', two: 'two' }, - }); - - expect(searchState).toEqual({ page: 1, menu: { one: '', two: 'two' } }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue }, - { - menu: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - menu: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue }, - searchState - ); - expect(searchState).toEqual({ - menu: {}, - another: { searchState: 'searchState' }, - }); - }); - - it('calling searchForItems return the right searchForItems parameters with limit', () => { - const parameters = connect.searchForFacetValues( - { attribute: 'ok', limit: 15, showMoreLimit: 25, showMore: false }, - {}, - 'yep' - ); - - expect(parameters).toEqual({ - facetName: 'ok', - query: 'yep', - maxFacetHits: 15, - }); - }); - - it('calling searchForItems return the right searchForItems parameters with showMoreLimit', () => { - const parameters = connect.searchForFacetValues( - { attribute: 'ok', limit: 15, showMoreLimit: 25, showMore: true }, - {}, - 'yep' - ); - - expect(parameters).toEqual({ - facetName: 'ok', - query: 'yep', - maxFacetHits: 25, - }); - }); - - it('if not searchable: uses a static sortBy order', () => { - const results = { - getFacetValues: jest.fn(() => [ - { - name: 'oy', - escapedValue: 'oy', - isRefined: true, - count: 10, - }, - { - name: 'wat', - escapedValue: 'wat', - isRefined: false, - count: 20, - }, - ]), - getFacetByName: () => true, - hits: [], - }; - - const { defaultProps } = connect; - props = connect.getProvidedProps( - { ...defaultProps, attribute: 'ok', contextValue }, - {}, - { results } - ); - - expect(results.getFacetValues).toHaveBeenCalledWith('ok', { - sortBy: ['count:desc', 'name:asc'], - facetOrdering: true, - }); - - expect(props.items).toEqual([ - { - value: 'oy', - label: 'oy', - isRefined: true, - count: 10, - }, - { - value: 'wat', - label: 'wat', - isRefined: false, - count: 20, - }, - ]); - }); - - it('if searchable: use the default sortBy order', () => { - const results = { - getFacetValues: jest.fn(() => [ - { - name: 'oy', - escapedValue: 'oy', - isRefined: true, - count: 10, - }, - { - name: 'wat', - escapedValue: 'wat', - isRefined: false, - count: 20, - }, - ]), - getFacetByName: () => true, - hits: [], - }; - - const { defaultProps } = connect; - props = connect.getProvidedProps( - { - ...defaultProps, - attribute: 'ok', - searchable: true, - contextValue, - }, - {}, - { results } - ); - - expect(results.getFacetValues).toHaveBeenCalledWith('ok', { - sortBy: undefined, - facetOrdering: true, - }); - - expect(props.items).toEqual([ - { - value: 'oy', - label: 'oy', - isRefined: true, - count: 10, - }, - { - value: 'wat', - label: 'wat', - isRefined: false, - count: 20, - }, - ]); - }); - - it('computes canRefine based on the length of the transformed items list', () => { - const transformItems = () => []; - const results = { - getFacetValues: () => [ - { count: 1, id: 'test', isRefined: true, name: 'test' }, - ], - getFacetByName: () => true, - hits: [], - }; - - props = connect.getProvidedProps( - { attribute: 'ok', transformItems, contextValue }, - {}, - { results } - ); - - expect(props.canRefine).toEqual(false); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - const results = { - second: { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - }, - }; - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - {}, - {} - ); - expect(props).toEqual({ - items: [], - currentRefinement: null, - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - { indices: { second: { menu: { ok: 'wat' } } } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - { indices: { second: { menu: { ok: 'wat' } } } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { - attribute: 'ok', - defaultRefinement: 'wat', - contextValue, - indexContextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: 'wat', - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: null, - isFromSearch: false, - canRefine: false, - searchForItems: undefined, - }); - - results.second.getFacetValues.mockClear(); - results.second.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - escapedValue: 'wat', - isRefined: true, - count: 20, - }, - { - name: 'oy', - escapedValue: 'oy', - isRefined: false, - count: 10, - }, - ]); - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: 'oy', - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue, indexContextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { - attribute: 'ok', - showMore: true, - limit: 0, - showMoreLimit: 1, - contextValue, - indexContextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue, indexContextValue }, - {}, - { results }, - {}, - { - query: 'query', - ok: [ - { - value: 'wat', - escapedValue: 'wat', - count: 10, - highlighted: 'wat', - isRefined: false, - }, - ], - } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: false, - count: 10, - _highlightResult: { label: { value: 'wat' } }, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue, indexContextValue }, - {}, - { results }, - {}, - { query: '' } - ); - expect(props.items).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attribute: 'ok', transformItems, contextValue, indexContextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - value: 'wat', - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: 'oy', - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('if an item is equal to the currentRefinement, its value should be an empty string', () => { - const results = { - second: { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - }, - }; - results.second.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - escapedValue: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - { indices: { second: { menu: { ok: 'wat' } } } }, - { results } - ); - - expect(props.items).toEqual([ - { - value: '', - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { attribute: 'ok', contextValue, indexContextValue }, - { - indices: { - second: { otherKey: 'val', menu: { ok: 'wat', otherKey: 'val' } }, - }, - }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - second: { - page: 1, - otherKey: 'val', - menu: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - - nextState = connect.refine( - { - attribute: 'ok', - contextValue, - indexContextValue: { targetedIndex: 'second' }, - }, - { - indices: { - first: { otherKey: 'val', menu: { ok: 'wat', otherKey: 'val' } }, - }, - }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - first: { otherKey: 'val', menu: { ok: 'wat', otherKey: 'val' } }, - second: { page: 1, menu: { ok: 'yep' } }, - }, - }); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - limit: 1, - contextValue, - indexContextValue, - }, - { indices: { second: { menu: { ok: 'wat' } } } } - ); - expect(params).toEqual( - initSP - .addDisjunctiveFacet('ok') - .addDisjunctiveFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - describe('getMetaData', () => { - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { menu: { wot: 'wat' } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: 'wot: wat', - attribute: 'wot', - currentRefinement: 'wat', - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - }); - - it('registers escaped metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { menu: { wot: '\\-wat' } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: 'wot: -wat', - attribute: 'wot', - currentRefinement: '\\-wat', - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', contextValue, indexContextValue }, - { indices: { second: { menu: { one: 'one', two: 'two' } } } } - ); - - const searchState = metadata.items[0].value({ - indices: { second: { menu: { one: 'one', two: 'two' } } }, - }); - - expect(searchState).toEqual({ - indices: { second: { page: 1, menu: { one: '', two: 'two' } } }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue, indexContextValue }, - { - indices: { - first: { - random: { untouched: 'yes' }, - }, - second: { - menu: { name: 'searchState', name2: 'searchState2' }, - another: { searchState: 'searchState' }, - }, - }, - } - ); - - expect(searchState).toEqual({ - indices: { - first: { - random: { untouched: 'yes' }, - }, - second: { - another: { - searchState: 'searchState', - }, - menu: { - name2: 'searchState2', - }, - }, - }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - indices: { - first: { - random: { untouched: 'yes' }, - }, - second: { another: { searchState: 'searchState' }, menu: {} }, - }, - }); - }); - }); - - it('errors if searchable is used in a multi index context', () => { - expect(() => { - connect.getProvidedProps( - { - contextValue, - indexContextValue, - searchable: true, - }, - {}, - {} - ); - }).toThrowErrorMatchingInlineSnapshot( - `"react-instantsearch: searching in *List is not available when used inside a multi index context"` - ); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectNumericMenu.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectNumericMenu.js deleted file mode 100644 index 6073bc7345..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectNumericMenu.js +++ /dev/null @@ -1,710 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectNumericMenu'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectNumericMenu', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - const results = { - getFacetStats: () => ({ min: 0, max: 300 }), - getFacetByName: () => true, - hits: [], - }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { - items: [], - contextValue, - }, - {}, - { results } - ); - - expect(props).toEqual({ - items: [ - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [{ label: 'ALL' }], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { label: 'ALL', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [{ label: 'Ok', start: 100 }], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { label: 'Ok', value: '100:', isRefined: false, noRefinement: false }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [{ label: 'Not ok', end: 200 }], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { - label: 'Not ok', - value: ':200', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [ - { label: 'Ok', start: 100 }, - { label: 'Not ok', end: 200 }, - { label: 'Maybe ok?', start: 100, end: 200 }, - ], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { label: 'Ok', value: '100:', isRefined: false, noRefinement: false }, - { - label: 'Not ok', - value: ':200', - isRefined: false, - noRefinement: false, - }, - { - label: 'Maybe ok?', - value: '100:200', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [ - { label: 'is 0', start: 0, end: 0 }, - { label: 'in 0..0.5', start: 0, end: 0.5 }, - ], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { - label: 'is 0', - value: '0:0', - isRefined: false, - noRefinement: false, - }, - { - label: 'in 0..0.5', - value: '0:0.5', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - - props = connect.getProvidedProps( - { - items: [ - { label: 'is 0', start: 0, end: 0 }, - { label: 'in 0..10', start: 0, end: 10 }, - ], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { - label: 'is 0', - value: '0:0', - isRefined: false, - noRefinement: false, - }, - { - label: 'in 0..10', - value: '0:10', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - }); - - it('no items define', () => { - props = connect.getProvidedProps( - { attribute: 'ok', items: [], contextValue }, - { multiRange: { ok: 'wat' } }, - { results } - ); - expect(props).toEqual({ - items: [ - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: 'wat', - canRefine: true, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', items: [], contextValue }, - { multiRange: { ok: 'wat' } }, - {} - ); - expect(props).toEqual({ - items: [ - { label: 'All', value: '', isRefined: true, noRefinement: true }, - ], - currentRefinement: 'wat', - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', items: [], defaultRefinement: 'wat', contextValue }, - {}, - {} - ); - expect(props).toEqual({ - items: [ - { label: 'All', value: '', isRefined: true, noRefinement: true }, - ], - currentRefinement: 'wat', - canRefine: false, - }); - }); - - it('use the transform items props if passed', () => { - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { - items: [ - { label: 'Ok', start: 100 }, - { label: 'Not ok', end: 200 }, - { label: 'Maybe ok?', start: 100, end: 200 }, - ], - transformItems, - contextValue, - }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { label: 'Ok', value: '100:', isRefined: false, noRefinement: false }, - { - label: 'Not ok', - value: ':200', - isRefined: false, - noRefinement: false, - }, - { - label: 'Maybe ok?', - value: '100:200', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('compute the no refinement value for each item range when stats exists', () => { - props = connect.getProvidedProps( - { - items: [ - { label: '1', start: 100 }, - { label: '2', start: 400 }, - { label: '3', end: 200 }, - { label: '4', start: 100, end: 200 }, - { label: '5', start: 300 }, - { label: '6', start: 300, end: 300 }, - ], - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - items: [ - { label: '1', value: '100:', isRefined: false, noRefinement: false }, - { label: '2', value: '400:', isRefined: false, noRefinement: true }, - { label: '3', value: ':200', isRefined: false, noRefinement: false }, - { - label: '4', - value: '100:200', - isRefined: false, - noRefinement: false, - }, - { label: '5', value: '300:', isRefined: false, noRefinement: false }, - { - label: '6', - value: '300:300', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: '', - canRefine: true, - }); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { attribute: 'ok', contextValue }, - { otherKey: 'val', multiRange: { otherKey: 'val' } }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - multiRange: { ok: 'yep', otherKey: 'val' }, - }); - }); - - it('refines the corresponding numeric facet', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { facet: '' } - ); - expect(params.getNumericRefinements('facet')).toEqual({}); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: '100:' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [100], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: ':200' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '<=': [200], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: '100:200' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [100], - '<=': [200], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: '0:' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [0], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: ':0' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '<=': [0], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: '0:0' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [0], - '<=': [0], - }); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue }, - { multiRange: { facet: '0:0.5' } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [0], - '<=': [0.5], - }); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'ok', contextValue }, - {} - ); - expect(metadata).toEqual({ id: 'ok', index: 'index', items: [] }); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { - attribute: 'wot', - items: [ - { - label: 'YAY', - start: 100, - end: 200, - }, - ], - contextValue, - }, - { multiRange: { wot: '100:200' } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: 'wot: YAY', - // Ignore clear, we test it later - value: metadata.items[0].value, - attribute: 'wot', - currentRefinement: 'YAY', - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { - attribute: 'one', - items: [ - { - label: 'YAY', - start: 100, - end: 200, - }, - ], - contextValue, - }, - { multiRange: { one: '100:200', two: '200:400' } } - ); - - const searchState = metadata.items[0].value({ - multiRange: { one: '100:200', two: '200:400' }, - }); - - expect(searchState).toEqual({ - page: 1, - multiRange: { one: '', two: '200:400' }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue }, - { - multiRange: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - multiRange: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue }, - searchState - ); - expect(searchState).toEqual({ - multiRange: {}, - another: { searchState: 'searchState' }, - }); - }); - - it('computes canRefine based on the length of the transformed items list', () => { - const transformItems = () => []; - - props = connect.getProvidedProps( - { - items: [{ label: 'Ok', start: 100 }], - transformItems, - contextValue, - }, - {}, - { results } - ); - - expect(props.canRefine).toEqual(false); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - const results = { - second: { - getFacetStats: () => ({ min: 0, max: 300 }), - getFacetByName: () => true, - }, - }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { - attribute: 'ok', - items: [ - { label: 'Ok', start: 100 }, - { label: 'Not ok', end: 200 }, - { label: 'Maybe ok?', start: 100, end: 200 }, - ], - contextValue, - indexContextValue, - }, - { indices: { second: { multiRange: { ok: 'wat' } } } }, - { results } - ); - expect(props).toEqual({ - items: [ - { label: 'Ok', value: '100:', isRefined: false, noRefinement: false }, - { - label: 'Not ok', - value: ':200', - isRefined: false, - noRefinement: false, - }, - { - label: 'Maybe ok?', - value: '100:200', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ], - currentRefinement: 'wat', - canRefine: true, - }); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { attribute: 'ok', contextValue, indexContextValue }, - { - indices: { - second: { otherKey: 'val', multiRange: { otherKey: 'val' } }, - }, - }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - second: { - otherKey: 'val', - page: 1, - multiRange: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - - nextState = connect.refine( - { - attribute: 'ok', - contextValue, - indexContextValue, - }, - { - indices: { - second: { - otherKey: 'val', - multiRange: { ok: 'yep', otherKey: 'val' }, - }, - }, - }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - second: { - page: 1, - otherKey: 'val', - multiRange: { ok: 'yep', otherKey: 'val' }, - }, - }, - }); - }); - - it('refines the corresponding numeric facet', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { attribute: 'facet', contextValue, indexContextValue }, - { indices: { second: { multiRange: { facet: '100:' } } } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [100], - }); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { - attribute: 'wot', - items: [ - { - label: 'YAY', - start: 100, - end: 200, - }, - ], - contextValue, - indexContextValue, - }, - { indices: { second: { multiRange: { wot: '100:200' } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: 'wot: YAY', - // Ignore clear, we test it later - value: metadata.items[0].value, - attribute: 'wot', - currentRefinement: 'YAY', - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { - attribute: 'one', - items: [ - { - label: 'YAY', - start: 100, - end: 200, - }, - ], - contextValue, - indexContextValue, - }, - { - indices: { - second: { multiRange: { one: '100:200', two: '200:400' } }, - }, - } - ); - - const searchState = metadata.items[0].value({ - indices: { second: { multiRange: { one: '100:200', two: '200:400' } } }, - }); - - expect(searchState).toEqual({ - indices: { - second: { page: 1, multiRange: { one: '', two: '200:400' } }, - }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue, indexContextValue }, - { - indices: { - first: { - another: { name: 'searchState' }, - }, - second: { - multiRange: { name: 'searchState', name2: 'searchState' }, - }, - }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { - first: { - another: { name: 'searchState' }, - }, - second: { multiRange: { name2: 'searchState' } }, - }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - indices: { - first: { - another: { name: 'searchState' }, - }, - second: { multiRange: {} }, - }, - another: { searchState: 'searchState' }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectPagination.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectPagination.js deleted file mode 100644 index 7f730b2594..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectPagination.js +++ /dev/null @@ -1,189 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectPagination'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectPagination', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { contextValue }, - {}, - { results: { nbPages: 666, hits: [] } } - ); - expect(props).toEqual({ - currentRefinement: 1, - nbPages: 666, - canRefine: true, - }); - - props = connect.getProvidedProps( - { contextValue }, - { page: 5 }, - { results: { nbPages: 666, hits: [] } } - ); - expect(props).toEqual({ - currentRefinement: 5, - nbPages: 666, - canRefine: true, - }); - - props = connect.getProvidedProps( - { contextValue }, - { page: '5' }, - { results: { nbPages: 666, hits: [] } } - ); - expect(props).toEqual({ - currentRefinement: 5, - nbPages: 666, - canRefine: true, - }); - - props = connect.getProvidedProps( - { contextValue }, - { page: '1' }, - { results: { nbPages: 1, hits: [] } } - ); - expect(props).toEqual({ - currentRefinement: 1, - nbPages: 1, - canRefine: false, - }); - }); - - it("doesn't render when no results are available", () => { - props = connect.getProvidedProps({ contextValue }, {}, {}); - expect(props).toBe(null); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 'yep', - }); - }); - - it('refines the page parameter', () => { - const initSP = new SearchParameters(); - params = connect.getSearchParameters( - initSP, - { contextValue }, - { page: 667 } - ); - expect(params.page).toBe(666); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata({ contextValue }, {}); - expect(metadata).toEqual({ id: 'page' }); - }); - - it('should return the right searchState when clean up', () => { - const newState = connect.cleanUp( - { contextValue }, - { - page: { searchState: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(newState).toEqual({ another: { searchState: 'searchState' } }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - {}, - { results: { second: { nbPages: 666 } } } - ); - expect(props).toEqual({ - currentRefinement: 1, - nbPages: 666, - canRefine: true, - }); - - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - { indices: { second: { page: 5 } } }, - { results: { second: { nbPages: 666 } } } - ); - expect(props).toEqual({ - currentRefinement: 5, - nbPages: 666, - canRefine: true, - }); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { contextValue, indexContextValue }, - { indices: { second: { otherKey: 'val' } } }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - second: { - otherKey: 'val', - page: 'yep', - }, - }, - }); - - nextState = connect.refine( - { - contextValue: { mainTargetedIndex: 'second' }, - indexContextValue: { targetedIndex: 'second' }, - }, - { indices: { second: { otherKey: 'val', page: 'yep' } } }, - 'yep' - ); - expect(nextState).toEqual({ - indices: { - second: { otherKey: 'val', page: 'yep' }, - }, - }); - }); - - it('refines the page parameter', () => { - const initSP = new SearchParameters(); - params = connect.getSearchParameters( - initSP, - { contextValue, indexContextValue }, - { indices: { second: { page: 667 } } } - ); - expect(params.page).toBe(666); - }); - - it('should return the right searchState when clean up', () => { - const newState = connect.cleanUp( - { contextValue, indexContextValue }, - { - indices: { - second: { - page: { searchState: 'searchState' }, - another: { searchState: 'searchState' }, - }, - }, - } - ); - expect(newState).toEqual({ - indices: { second: { another: { searchState: 'searchState' } } }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.jsdom.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.jsdom.js deleted file mode 100644 index cd1b32d9c9..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.jsdom.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import connect from '../connectPoweredBy'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectPoweredBy', () => { - const { getProvidedProps } = connect; - - it('provides the correct props to the component', () => { - const props = getProvidedProps(); - - expect(props).toEqual({ - url: 'https://www.algolia.com/?utm_source=react-instantsearch&utm_medium=website&utm_content=localhost&utm_campaign=poweredby', - }); - }); - - it('handles react native environment in window without location object', () => { - const originalWindow = { ...window }; - const windowSpy = jest.spyOn(global, 'window', 'get'); - const { location, ...windowWithoutLocation } = originalWindow; - windowSpy.mockImplementation(() => windowWithoutLocation); - const props = getProvidedProps(); - expect(props).toEqual({ - url: 'https://www.algolia.com/?utm_source=react-instantsearch&utm_medium=website&utm_content=&utm_campaign=poweredby', - }); - windowSpy.mockRestore(); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.node.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.node.js deleted file mode 100644 index 3ed6d4067b..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectPoweredBy.node.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @jest-environment node - */ - -import connect from '../connectPoweredBy'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectPoweredBy', () => { - const { getProvidedProps } = connect; - - it('provides the correct props to the component', () => { - const props = getProvidedProps(); - - expect(props).toEqual({ - url: 'https://www.algolia.com/?utm_source=react-instantsearch&utm_medium=website&utm_content=&utm_campaign=poweredby', - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectQueryRules.ts b/packages/react-instantsearch-core/src/connectors/__tests__/connectQueryRules.ts deleted file mode 100644 index 6708c35ef7..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectQueryRules.ts +++ /dev/null @@ -1,686 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connectReal from '../connectQueryRules'; - -import type { - ConnectorDescription, - ConnectedProps, -} from '../../core/createConnector'; -import type { QueryRulesProps } from '../connectQueryRules'; - -jest.mock( - '../../core/createConnector', - () => (connector: ConnectorDescription) => connector -); -// our mock implementation is diverging from the regular createConnector, -// so we redefine it as `any` here, since we have no more information -// @TODO: refactor these tests to work better with TS -const connect: any = connectReal; - -describe('connectQueryRules', () => { - const defaultProps: QueryRulesProps = { - transformItems: (items) => items, - trackedFilters: {}, - transformRuleContexts: (ruleContexts) => ruleContexts, - }; - - describe('single index', () => { - const indexName = 'index'; - const contextValue: any = { mainTargetedIndex: indexName }; - const defaultPropsSingleIndex = { - ...defaultProps, - contextValue, - }; - - describe('default', () => { - it('without userData provides the correct props to the component', () => { - const props: ConnectedProps = defaultPropsSingleIndex; - const searchState = {}; - const searchResults = { - results: { [indexName]: { userData: undefined } }, - }; - - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [], - canRefine: false, - }); - }); - - it('with userData provides the correct props to the component', () => { - const props: ConnectedProps = defaultPropsSingleIndex; - const searchState = {}; - const searchResults = { - results: { - [indexName]: { userData: [{ banner: 'image.png' }] }, - }, - }; - - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [{ banner: 'image.png' }], - canRefine: true, - }); - }); - }); - - describe('transformItems', () => { - it('transforms items before passing the props to the component', () => { - const transformItemsSpy = jest.fn(() => [ - { banner: 'image-transformed.png' }, - ]); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - transformItems: transformItemsSpy, - }; - const searchState = {}; - const searchResults = { - results: { - [indexName]: { userData: [{ banner: 'image.png' }] }, - }, - }; - - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [{ banner: 'image-transformed.png' }], - canRefine: true, - }); - expect(transformItemsSpy).toHaveBeenCalledTimes(1); - expect(transformItemsSpy).toHaveBeenCalledWith([ - { banner: 'image.png' }, - ]); - }); - }); - - describe('trackedFilters', () => { - it('does not set ruleContexts without search state and trackedFilters', () => { - const props: ConnectedProps = defaultPropsSingleIndex; - const searchState = {}; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual(undefined); - }); - - it('does not set ruleContexts with search state but without tracked filters', () => { - const props: ConnectedProps = defaultPropsSingleIndex; - const searchState = { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual(undefined); - }); - - it('does not reset initial ruleContexts with trackedFilters', () => { - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - price: (values) => values, - }, - }; - const searchState = {}; - const searchParameters = connect.getSearchParameters( - SearchParameters.make({ - ruleContexts: ['initial-rule'], - }), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual(['initial-rule']); - }); - - it('does not throw an error with search state that contains `undefined` value', () => { - const props: QueryRulesProps = { - ...defaultProps, - trackedFilters: { - price: (values) => values, - }, - }; - - const searchState = { - refinementList: undefined, - }; - - expect(() => { - connect.getSearchParameters( - SearchParameters.make({}), - props, - searchState - ); - }).not.toThrow(); - }); - - it('sets ruleContexts based on range', () => { - const priceSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - price: priceSpy, - }, - }; - const searchState = { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(priceSpy).toHaveBeenCalledTimes(1); - expect(priceSpy).toHaveBeenCalledWith([20, 3000]); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-price-20', - 'ais-price-3000', - ]); - }); - - it('sets ruleContexts based on refinementList', () => { - const fruitSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - fruit: fruitSpy, - }, - }; - const searchState = { - refinementList: { - fruit: ['lemon', 'orange'], - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(fruitSpy).toHaveBeenCalledTimes(1); - expect(fruitSpy).toHaveBeenCalledWith(['lemon', 'orange']); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-fruit-lemon', - 'ais-fruit-orange', - ]); - }); - - it('sets ruleContexts based on hierarchicalMenu', () => { - const productsSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - products: productsSpy, - }, - }; - const searchState = { - hierarchicalMenu: { - products: 'Laptops > Surface', - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(productsSpy).toHaveBeenCalledTimes(1); - expect(productsSpy).toHaveBeenCalledWith(['Laptops > Surface']); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-products-Laptops_Surface', - ]); - }); - - it('sets ruleContexts based on menu', () => { - const brandsSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - brands: brandsSpy, - }, - }; - const searchState = { - menu: { - brands: 'Sony', - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(brandsSpy).toHaveBeenCalledTimes(1); - expect(brandsSpy).toHaveBeenCalledWith(['Sony']); - expect(searchParameters.ruleContexts).toEqual(['ais-brands-Sony']); - }); - - it('sets ruleContexts based on multiRange', () => { - const rankSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - rank: rankSpy, - }, - }; - const searchState = { - multiRange: { - rank: '2:5', - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(rankSpy).toHaveBeenCalledTimes(1); - expect(rankSpy).toHaveBeenCalledWith(['2', '5']); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-rank-2', - 'ais-rank-5', - ]); - }); - - it('sets ruleContexts based on toggle', () => { - const freeShippingSpy = jest.fn((values) => values); - const availableInStockSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - freeShipping: freeShippingSpy, - availableInStock: availableInStockSpy, - }, - }; - const searchState = { - toggle: { - freeShipping: true, - availableInStock: false, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(freeShippingSpy).toHaveBeenCalledTimes(1); - expect(freeShippingSpy).toHaveBeenCalledWith([true]); - expect(availableInStockSpy).toHaveBeenCalledTimes(1); - expect(availableInStockSpy).toHaveBeenCalledWith([false]); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-freeShipping-true', - 'ais-availableInStock-false', - ]); - }); - - it('escapes all rule contexts before passing them to search parameters', () => { - const brandSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - brand: brandSpy, - }, - }; - const searchState = { - refinementList: { - brand: ['Insignia™', '© Apple'], - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(brandSpy).toHaveBeenCalledTimes(1); - expect(brandSpy).toHaveBeenCalledWith(['Insignia™', '© Apple']); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-brand-Insignia_', - 'ais-brand-_Apple', - ]); - }); - - it('slices and warns in development when more than 10 rule contexts are applied', () => { - // We need to simulate being in development mode and to mock the global console object - // in this test to assert that development warnings are displayed correctly. - const originalNodeEnv = process.env.NODE_ENV; - process.env.NODE_ENV = 'development'; - const warnSpy = jest - .spyOn(console, 'warn') - .mockImplementation(() => {}); - - const brandFacetRefinements = [ - 'Insignia', - 'Canon', - 'Dynex', - 'LG', - 'Metra', - 'Sony', - 'HP', - 'Apple', - 'Samsung', - 'Speck', - 'PNY', - ]; - - expect(brandFacetRefinements).toHaveLength(11); - - const brandSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - brand: brandSpy, - }, - }; - const searchState = { - refinementList: { - brand: brandFacetRefinements, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(warnSpy).toHaveBeenCalledTimes(1); - expect(warnSpy) - .toHaveBeenCalledWith(`The maximum number of \`ruleContexts\` is 10. They have been sliced to that limit. -Consider using \`transformRuleContexts\` to minimize the number of rules sent to Algolia.`); - - expect(brandSpy).toHaveBeenCalledTimes(1); - expect(brandSpy).toHaveBeenCalledWith([ - 'Insignia', - 'Canon', - 'Dynex', - 'LG', - 'Metra', - 'Sony', - 'HP', - 'Apple', - 'Samsung', - 'Speck', - 'PNY', - ]); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-brand-Insignia', - 'ais-brand-Canon', - 'ais-brand-Dynex', - 'ais-brand-LG', - 'ais-brand-Metra', - 'ais-brand-Sony', - 'ais-brand-HP', - 'ais-brand-Apple', - 'ais-brand-Samsung', - 'ais-brand-Speck', - ]); - - process.env.NODE_ENV = originalNodeEnv; - warnSpy.mockRestore(); - }); - }); - - describe('transformRuleContexts', () => { - it('transform rule contexts before adding them to search parameters', () => { - const priceSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsSingleIndex, - trackedFilters: { - price: priceSpy, - }, - transformRuleContexts: (rules) => - rules.map((rule) => rule.replace('ais-', 'transformed-')), - }; - const searchState = { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(priceSpy).toHaveBeenCalledTimes(1); - expect(priceSpy).toHaveBeenCalledWith([20, 3000]); - expect(searchParameters.ruleContexts).toEqual([ - 'transformed-price-20', - 'transformed-price-3000', - ]); - }); - }); - }); - - describe('multi index', () => { - const firstIndexName = 'firstIndex'; - const secondIndexName = 'secondIndex'; - - const contextValue: any = { mainTargetedIndex: firstIndexName }; - const indexContextValue: any = { targetedIndex: secondIndexName }; - - const defaultPropsMultiIndex = { - ...defaultProps, - contextValue, - indexContextValue, - }; - - it('without userData provides the correct props to the component', () => { - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - }; - const searchState = {}; - const searchResults = { - results: { [secondIndexName]: { userData: undefined } }, - }; - - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [], - canRefine: false, - }); - }); - - it('with userData provides the correct props to the component', () => { - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - }; - const searchState = {}; - const searchResults = { - results: { - [secondIndexName]: { userData: [{ banner: 'image.png' }] }, - }, - }; - - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [{ banner: 'image.png' }], - canRefine: true, - }); - }); - - describe('transformItems', () => { - it('transforms items before passing the props to the component', () => { - const transformItemsSpy = jest.fn(() => [ - { banner: 'image-transformed.png' }, - ]); - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - transformItems: transformItemsSpy, - }; - const searchState = {}; - const searchResults = { - results: { - [secondIndexName]: { userData: [{ banner: 'image.png' }] }, - }, - }; - expect( - connect.getProvidedProps(props, searchState, searchResults) - ).toEqual({ - items: [{ banner: 'image-transformed.png' }], - canRefine: true, - }); - expect(transformItemsSpy).toHaveBeenCalledTimes(1); - expect(transformItemsSpy).toHaveBeenCalledWith([ - { banner: 'image.png' }, - ]); - }); - }); - - describe('trackedFilters', () => { - it('does not set ruleContexts without search state and trackedFilters', () => { - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - }; - const searchState = {}; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual(undefined); - }); - - it('does not set ruleContexts with search state but without tracked filters', () => { - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - }; - const searchState = { - indices: { - [secondIndexName]: { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual(undefined); - }); - - it('sets ruleContexts based on range', () => { - const priceSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - trackedFilters: { - price: priceSpy, - }, - }; - const searchState = { - indices: { - [secondIndexName]: { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(priceSpy).toHaveBeenCalledTimes(1); - expect(priceSpy).toHaveBeenCalledWith([20, 3000]); - expect(searchParameters.ruleContexts).toEqual([ - 'ais-price-20', - 'ais-price-3000', - ]); - }); - - it('sets empty ruleContexts without search state', () => { - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - trackedFilters: { - price: (values) => values, - }, - }; - const searchState = {}; - - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(searchParameters.ruleContexts).toEqual([]); - }); - }); - - describe('transformRuleContexts', () => { - it('transform rule contexts before adding them to search parameters', () => { - const priceSpy = jest.fn((values) => values); - const props: ConnectedProps = { - ...defaultPropsMultiIndex, - trackedFilters: { - price: priceSpy, - }, - transformRuleContexts: (rules) => - rules.map((rule) => rule.replace('ais-', 'transformed-')), - }; - const searchState = { - indices: { - [secondIndexName]: { - range: { - price: { - min: 20, - max: 3000, - }, - }, - }, - }, - }; - const searchParameters = connect.getSearchParameters( - new SearchParameters(), - props, - searchState - ); - - expect(priceSpy).toHaveBeenCalledTimes(1); - expect(priceSpy).toHaveBeenCalledWith([20, 3000]); - expect(searchParameters.ruleContexts).toEqual([ - 'transformed-price-20', - 'transformed-price-3000', - ]); - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectRange.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectRange.js deleted file mode 100644 index af11a01f02..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectRange.js +++ /dev/null @@ -1,1739 +0,0 @@ -import { SearchParameters, SearchResults } from 'algoliasearch-helper'; - -import connect from '../connectRange'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectRange', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps.call( - {}, - { attribute: 'ok', min: 5, max: 10, precision: 2, contextValue }, - {}, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 5, max: 10 }, - count: [], - canRefine: false, - precision: 2, - }); - - let results = { - getFacetStats: () => ({ min: 5, max: 10 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 2, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 5, max: 10 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 2, - }); - - results = { - getFacetStats: () => ({ min: 0.1, max: 9.9 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 0, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0, - max: 10, - currentRefinement: { min: 0, max: 10 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 0, - }); - - results = { - getFacetStats: () => ({ min: 0.1, max: 9.9 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 2, - min: 0.1, - max: 9.9, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0.1, - max: 9.9, - currentRefinement: { min: 0.1, max: 9.9 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 2, - }); - - results = { - getFacetStats: () => ({ min: 0.1234, max: 9.5678 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 0, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0, - max: 10, - currentRefinement: { min: 0, max: 10 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 0, - }); - - results = { - getFacetStats: () => ({ min: 0.1234, max: 9.5678 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 1, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0.1, - max: 9.6, - currentRefinement: { min: 0.1, max: 9.6 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 1, - }); - - results = { - getFacetStats: () => ({ min: 0.1234, max: 9.5678 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 2, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0.12, - max: 9.57, - currentRefinement: { min: 0.12, max: 9.57 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 2, - }); - - results = { - getFacetStats: () => ({ min: 0.1234, max: 9.5678 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 3, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: 0.123, - max: 9.568, - currentRefinement: { min: 0.123, max: 9.568 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 3, - }); - - results = { - getFacetByName: () => false, - getFacetStats: () => {}, - getFacetValues: () => [], - hits: [], - }; - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 2, - contextValue, - }, - {}, - { results } - ); - expect(props).toEqual({ - min: undefined, - max: undefined, - currentRefinement: { - min: undefined, - max: undefined, - }, - count: [], - canRefine: false, - precision: 2, - }); - - props = connect.getProvidedProps.call( - {}, - { attribute: 'ok', precision: 2, contextValue }, - { ok: { min: 6, max: 9 } }, - {} - ); - expect(props).toEqual({ - min: undefined, - max: undefined, - currentRefinement: { - min: undefined, - max: undefined, - }, - count: [], - canRefine: false, - precision: 2, - }); - - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - precision: 2, - contextValue, - }, - { - range: { ok: { min: 6, max: 9 } }, - }, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6, max: 9 }, - count: [], - canRefine: false, - precision: 2, - }); - - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - precision: 2, - contextValue, - }, - { - range: { ok: { min: '6', max: '9' } }, - }, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6, max: 9 }, - count: [], - canRefine: false, - precision: 2, - }); - - // With a precision of 0 -> parseInt - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - precision: 0, - contextValue, - }, - { - range: { ok: { min: '6.9', max: '9.6' } }, - }, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6, max: 9 }, - count: [], - canRefine: false, - precision: 0, - }); - - // With a precision of > 0 -> parseFloat - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - precision: 1, - contextValue, - }, - { - range: { ok: { min: '6.9', max: '9.6' } }, - }, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6.9, max: 9.6 }, - count: [], - canRefine: false, - precision: 1, - }); - - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - defaultRefinement: { min: 6, max: 9 }, - precision: 2, - contextValue, - }, - {}, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6, max: 9 }, - count: [], - canRefine: false, - precision: 2, - }); - - props = connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - precision: 2, - contextValue, - }, - {}, - { - results: new SearchResults(new SearchParameters(), [{ hits: [] }]), - } - ); - expect(props).toEqual({ - min: undefined, - max: undefined, - currentRefinement: { - min: undefined, - max: undefined, - }, - count: [], - canRefine: false, - precision: 2, - }); - - expect(() => - connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - defaultRefinement: { min: 4, max: 9 }, - precision: 2, - contextValue, - }, - {}, - {} - ) - ).toThrow("You can't provide min value lower than range."); - - expect(() => - connect.getProvidedProps.call( - {}, - { - attribute: 'ok', - min: 5, - max: 10, - defaultRefinement: { min: 6, max: 11 }, - precision: 2, - contextValue, - }, - {}, - {} - ) - ).toThrow("You can't provide max value greater than range."); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'ok', contextValue }, - { otherKey: 'val', range: { otherKey: { min: 1, max: 2 } } }, - { min: 3, max: 5 } - ); - expect(nextState).toEqual({ - page: 1, - otherKey: 'val', - range: { ok: { min: 3, max: 5 }, otherKey: { min: 1, max: 2 } }, - }); - }); - - it('calling refine with non finite values should fail', () => { - function shouldNotRefineWithNaN() { - connect.refine.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'ok', contextValue }, - { otherKey: 'val', range: { otherKey: { min: 1, max: 2 } } }, - { min: NaN, max: 5 } - ); - } - expect(shouldNotRefineWithNaN).toThrow( - "You can't provide non finite values to the range connector" - ); - - function shouldNotRefineWithNull() { - connect.refine.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'ok', contextValue }, - { otherKey: 'val', range: { otherKey: { min: 1, max: 2 } } }, - { min: null, max: 5 } - ); - } - expect(shouldNotRefineWithNull).toThrow( - "You can't provide non finite values to the range connector" - ); - }); - - it('refines the corresponding numeric facet', () => { - params = connect.getSearchParameters.call( - { - _currentRange: { - min: 10, - max: 30, - }, - }, - new SearchParameters(), - { attribute: 'facet', contextValue }, - { range: { facet: { min: 10, max: 30 } } } - ); - - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [10], - '<=': [30], - }); - - params = connect.getSearchParameters.call( - { - _currentRange: { - min: 10, - max: 30, - }, - }, - new SearchParameters(), - { attribute: 'facet', min: 10, max: 30, contextValue }, - {} - ); - - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [10], - '<=': [30], - }); - }); - - it('registers its filter in metadata', () => { - let metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue }, - { range: { wot: { min: 5 } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: '5 <= wot', - attribute: 'wot', - currentRefinement: { min: 5, max: 100 }, - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - - const searchState = metadata.items[0].value({ - range: { wot: { min: 5 } }, - }); - expect(searchState).toEqual({ - page: 1, - range: { - wot: { - min: undefined, - max: undefined, - }, - }, - }); - - metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue }, - { range: { wot: { max: 10 } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: 'wot <= 10', - attribute: 'wot', - currentRefinement: { min: 0, max: 10 }, - value: metadata.items[0].value, - }, - ], - }); - - metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue }, - { range: { wot: { min: 5, max: 10 } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: '5 <= wot <= 10', - attribute: 'wot', - currentRefinement: { min: 5, max: 10 }, - value: metadata.items[0].value, - }, - ], - }); - - metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue }, - { range: { wot: { min: 0, max: 100 } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'one', contextValue }, - { range: { one: { min: 5 }, two: { max: 4 } } } - ); - - const searchState = metadata.items[0].value({ - range: { one: { min: 5 }, two: { max: 4 } }, - }); - - expect(searchState).toEqual({ - page: 1, - range: { - two: { - max: 4, - }, - one: { - min: undefined, - max: undefined, - }, - }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp.call( - {}, - { attribute: 'name', contextValue }, - { - range: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - range: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp.call( - {}, - { attribute: 'name2', contextValue }, - searchState - ); - expect(searchState).toEqual({ - range: {}, - another: { searchState: 'searchState' }, - }); - }); - - describe('refine', () => { - it('expect to refine when values are in range', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - const nextRefinement = { - min: 10, - max: 90, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine when values are parsable integer', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - const nextRefinement = { - min: '10', - max: '90', - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine when values are parsable float', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - const nextRefinement = { - min: '10.15', - max: '90.85', - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10.15, - max: 90.85, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine min at range bound when defined', () => { - const thisArgs = { - _currentRange: { min: 10, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - min: 10, - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - const nextRefinement = { - min: 10, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine max at range bound when defined', () => { - const thisArgs = { - _currentRange: { min: 0, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - max: 90, - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - const nextRefinement = { - max: 90, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine min when user bound are set and value is nullable', () => { - const thisArgs = { - _currentRange: { min: 10, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - min: 10, - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 20, - max: 90, - }, - }, - }; - - const nextRefinement = { - min: undefined, - max: 90, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to refine max when user bound are set and value is nullable', () => { - const thisArgs = { - _currentRange: { min: 0, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - max: 90, - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 10, - max: 90, - }, - }, - }; - - const nextRefinement = { - min: 10, - max: undefined, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset min with undefined', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 5, - max: 10, - }, - }, - }; - - const nextRefinement = { - min: undefined, - max: 10, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: undefined, - max: 10, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset max with undefined', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 5, - max: 10, - }, - }, - }; - - const nextRefinement = { - min: undefined, - max: 10, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: undefined, - max: 10, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset min with empty string', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 5, - max: 10, - }, - }, - }; - - const nextRefinement = { - min: '', - max: 10, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: undefined, - max: 10, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset max with empty string', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 5, - max: 10, - }, - }, - }; - - const nextRefinement = { - min: 5, - max: '', - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 5, - max: undefined, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset min when value is at bound and no bound are defined', () => { - const thisArgs = { - _currentRange: { min: 10, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 20, - max: 90, - }, - }, - }; - - const nextRefinement = { - min: 10, - max: 90, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: undefined, - max: 90, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to reset max when value is at bound and no bound are defined', () => { - const thisArgs = { - _currentRange: { min: 0, max: 100 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = { - otherKey: 'val', - range: { - otherKey: { - min: 1, - max: 2, - }, - ok: { - min: 10, - max: 90, - }, - }, - }; - - const nextRefinement = { - min: 10, - max: 100, - }; - - const actual = connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ); - - const expectation = { - page: 1, - otherKey: 'val', - range: { - ok: { - min: 10, - max: undefined, - }, - otherKey: { - min: 1, - max: 2, - }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to throw an error when min is invalid', () => { - const thisArgs = { - _currentRange: { min: 0, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = {}; - - const nextRefinement = { - min: 'kdsjhfkd', - }; - - expect(() => - connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ) - ).toThrow("You can't provide non finite values to the range connector"); - }); - - it('expect to throw an error when max is invalid', () => { - const thisArgs = { - _currentRange: { min: 0, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - }; - - const searchState = {}; - - const nextRefinement = { - max: 'kdsjhfkd', - }; - - expect(() => - connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ) - ).toThrow("You can't provide non finite values to the range connector"); - }); - - it('expect to throw an error when min is out of range', () => { - const thisArgs = { - _currentRange: { min: 10, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - min: 10, - }; - - const searchState = {}; - - const nextRefinement = { - min: 0, - }; - - expect(() => - connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ) - ).toThrow("You can't provide min value lower than range."); - }); - - it('expect to throw an error when max is out of range', () => { - const thisArgs = { - _currentRange: { min: 10, max: 90 }, - }; - - const propsForRefine = { - attribute: 'ok', - max: 100, - }; - - const searchState = {}; - - const nextRefinement = { - max: 110, - }; - - expect(() => - connect.refine.call( - thisArgs, - propsForRefine, - searchState, - nextRefinement - ) - ).toThrow("You can't provide max value greater than range."); - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - const results = { - second: { - getFacetStats: () => ({ min: 5, max: 10 }), - getFacetValues: () => [ - { name: '5', count: 10 }, - { name: '2', count: 20 }, - ], - getFacetByName: () => true, - }, - }; - const instance = {}; - - props = connect.getProvidedProps.call( - instance, - { attribute: 'ok', precision: 2, contextValue, indexContextValue }, - {}, - { results } - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 5, max: 10 }, - count: [ - { value: '5', count: 10 }, - { value: '2', count: 20 }, - ], - canRefine: true, - precision: 2, - }); - - props = connect.getProvidedProps.call( - instance, - { - attribute: 'ok', - min: 5, - max: 10, - precision: 2, - contextValue, - indexContextValue, - }, - { - indices: { second: { range: { ok: { min: 6, max: 9 } } } }, - }, - {} - ); - expect(props).toEqual({ - min: 5, - max: 10, - currentRefinement: { min: 6, max: 9 }, - count: [], - canRefine: false, - precision: 2, - }); - - props = connect.getProvidedProps.call( - instance, - { - attribute: 'ok', - precision: 2, - contextValue, - indexContextValue, - }, - {}, - { - results: { - second: new SearchResults(new SearchParameters(), [{ hits: [] }]), - }, - } - ); - expect(props).toEqual({ - min: undefined, - max: undefined, - currentRefinement: { - min: undefined, - max: undefined, - }, - count: [], - canRefine: false, - precision: 2, - }); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'ok', contextValue, indexContextValue }, - { - otherKey: 'val', - indices: { second: { range: { otherKey: { min: 1, max: 2 } } } }, - }, - { min: 3, max: 5 } - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { - second: { - page: 1, - range: { ok: { min: 3, max: 5 }, otherKey: { min: 1, max: 2 } }, - }, - }, - }); - - nextState = connect.refine.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { - attribute: 'ok', - contextValue, - indexContextValue: { targetedIndex: 'first' }, - }, - { - otherKey: 'val', - indices: { second: { range: { otherKey: { min: 1, max: 2 } } } }, - }, - { min: 3, max: 5 } - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { - first: { page: 1, range: { ok: { min: 3, max: 5 } } }, - second: { range: { otherKey: { min: 1, max: 2 } } }, - }, - }); - }); - - it('refines the corresponding numeric facet', () => { - params = connect.getSearchParameters( - new SearchParameters(), - { attribute: 'facet', contextValue, indexContextValue }, - { indices: { second: { range: { facet: { min: 10, max: 30 } } } } } - ); - expect(params.getNumericRefinements('facet')).toEqual({ - '>=': [10], - '<=': [30], - }); - }); - - it('registers its filter in metadata', () => { - let metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { range: { wot: { min: 5 } } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: '5 <= wot', - attribute: 'wot', - currentRefinement: { min: 5, max: 100 }, - // Ignore clear, we test it later - value: metadata.items[0].value, - }, - ], - }); - - const searchState = metadata.items[0].value({ - indices: { second: { range: { wot: { min: 5 } } } }, - }); - expect(searchState).toEqual({ - indices: { - second: { - page: 1, - range: { - wot: { - min: undefined, - max: undefined, - }, - }, - }, - }, - }); - - metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { range: { wot: { max: 10 } } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: 'wot <= 10', - attribute: 'wot', - currentRefinement: { min: 0, max: 10 }, - value: metadata.items[0].value, - }, - ], - }); - - metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { range: { wot: { max: 100 } } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata.call( - { - _currentRange: { min: 0, max: 100 }, - }, - { attribute: 'one', contextValue, indexContextValue }, - { indices: { second: { range: { one: { min: 5 }, two: { max: 4 } } } } } - ); - - const searchState = metadata.items[0].value({ - indices: { second: { range: { one: { min: 5 }, two: { max: 4 } } } }, - }); - - expect(searchState).toEqual({ - indices: { - second: { - page: 1, - range: { - one: { - min: undefined, - max: undefined, - }, - two: { - max: 4, - }, - }, - }, - }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue, indexContextValue }, - { - indices: { - second: { range: { name: 'searchState', name2: 'searchState' } }, - }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: { range: { name2: 'searchState' } } }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - another: { searchState: 'searchState' }, - indices: { second: { range: {} } }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectRefinementList.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectRefinementList.js deleted file mode 100644 index 3fd2b04dd4..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectRefinementList.js +++ /dev/null @@ -1,865 +0,0 @@ -import { SearchResults, SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectRefinementList'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectRefinementList', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - const results = { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - hits: [], - }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: [], - isFromSearch: false, - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - {} - ); - expect(props).toEqual({ - items: [], - currentRefinement: [], - isFromSearch: false, - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - { refinementList: { ok: ['wat'] } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: ['wat'], - isFromSearch: false, - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', defaultRefinement: ['wat'], contextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: ['wat'], - isFromSearch: false, - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', searchable: true, contextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: [], - isFromSearch: false, - canRefine: false, - searchable: true, - }); - - results.getFacetValues.mockClear(); - results.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - escapedValue: 'wat', - isRefined: true, - count: 20, - }, - { - name: 'oy', - escapedValue: 'oy', - isRefined: false, - count: 10, - }, - ]); - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: ['oy'], - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results }, - {}, - { - query: 'query', - ok: [ - { - value: 'wat', - escapedValue: 'wat', - count: 10, - highlighted: 'wat', - isRefined: false, - }, - ], - } - ); - expect(props.items).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: false, - count: 10, - _highlightResult: { label: { value: 'wat' } }, - }, - ]); - - props = connect.getProvidedProps( - { attribute: 'ok', limit: 1, contextValue }, - {}, - { results }, - {}, - { query: '' } - ); - expect(props.items).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - props = connect.getProvidedProps( - { - attribute: 'ok', - showMore: true, - limit: 0, - showMoreLimit: 1, - contextValue, - }, - {}, - { results } - ); - expect(props.items).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: true, - count: 20, - }, - ]); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { attribute: 'ok', transformItems, contextValue }, - {}, - { results } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { - value: ['wat'], - label: 'wat', - isRefined: true, - count: 20, - }, - { - value: ['oy'], - label: 'oy', - isRefined: false, - count: 10, - }, - ]); - expect(props.items).toEqual(['items']); - }); - - it('facetValues results should be provided as props if they exists', () => { - props = connect.getProvidedProps( - { attribute: 'ok', contextValue }, - {}, - { results }, - {}, - { - ok: [ - { - value: 'wat', - escapedValue: 'wat', - label: 'wat', - isRefined: true, - count: 20, - highlighted: 'wat', - }, - ], - } - ); - expect(props.items).toEqual([ - { - _highlightResult: { label: { value: 'wat' } }, - count: 20, - isRefined: true, - label: 'wat', - value: ['wat'], - }, - ]); - expect(props.isFromSearch).toBe(true); - }); - - it('facetValues have facetOrdering by default', () => { - const userProps = { - ...connect.defaultProps, - attribute: 'ok', - contextValue, - }; - const searchState = { - refinementList: { ok: ['wat'] }, - }; - const parameters = connect.getSearchParameters( - new SearchParameters(), - userProps, - searchState - ); - - const searchResults = new SearchResults(parameters, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - ok: { - order: ['lol'], - }, - }, - }, - }, - facets: { - ok: { - wat: 20, - lol: 2000, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(userProps, searchState, { - results: searchResults, - }); - - expect(providedProps.items).toEqual([ - { - count: 2000, - isRefined: false, - label: 'lol', - value: ['wat', 'lol'], - }, - { - count: 20, - isRefined: true, - label: 'wat', - value: [], - }, - ]); - expect(providedProps.isFromSearch).toBe(false); - }); - - it('facetValues results does not use facetOrdering if disabled', () => { - const userProps = { attribute: 'ok', facetOrdering: false, contextValue }; - const searchState = { - refinementList: { ok: ['wat'] }, - }; - const parameters = connect.getSearchParameters( - new SearchParameters(), - userProps, - searchState - ); - - const searchResults = new SearchResults(parameters, [ - { - hits: [], - renderingContent: { - facetOrdering: { - values: { - ok: { - order: ['lol'], - }, - }, - }, - }, - facets: { - ok: { - wat: 20, - lol: 2000, - }, - }, - }, - ]); - - const providedProps = connect.getProvidedProps(userProps, searchState, { - results: searchResults, - }); - - expect(providedProps.items).toEqual([ - { - count: 20, - isRefined: true, - label: 'wat', - value: [], - }, - { - count: 2000, - isRefined: false, - label: 'lol', - value: ['wat', 'lol'], - }, - ]); - expect(providedProps.isFromSearch).toBe(false); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { attribute: 'ok', contextValue }, - { otherKey: 'val', refinementList: { otherKey: ['val'] } }, - ['yep'] - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - refinementList: { ok: ['yep'], otherKey: ['val'] }, - }); - }); - - it("increases maxValuesPerFacet when it isn't big enough", () => { - const initSP = new SearchParameters({ maxValuesPerFacet: 100 }); - - params = connect.getSearchParameters( - initSP, - { - limit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - showMore: true, - showMoreLimit: 101, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(101); - - params = connect.getSearchParameters( - initSP, - { - limit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - - params = connect.getSearchParameters( - initSP, - { - showMore: true, - showMoreLimit: 99, - contextValue, - }, - {} - ); - expect(params.maxValuesPerFacet).toBe(100); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - operator: 'or', - limit: 1, - contextValue, - }, - { refinementList: { ok: ['wat'] } } - ); - expect(params).toEqual( - initSP - .addDisjunctiveFacet('ok') - .addDisjunctiveFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - operator: 'and', - limit: 1, - contextValue, - }, - { refinementList: { ok: ['wat'] } } - ); - expect(params).toEqual( - initSP - .addFacet('ok') - .addFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - describe('getMetadata', () => { - it('registers its id in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'ok', contextValue }, - {} - ); - expect(metadata).toEqual({ id: 'ok', index: 'index', items: [] }); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue }, - { refinementList: { wot: ['wat', 'wut'] } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: 'wot: ', - attribute: 'wot', - currentRefinement: ['wat', 'wut'], - value: metadata.items[0].value, - items: [ - { - label: 'wat', - value: metadata.items[0].items[0].value, - }, - { - label: 'wut', - value: metadata.items[0].items[1].value, - }, - ], - // Ignore value, we test it later - }, - ], - }); - }); - - it('registers escaped filterd in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue }, - { refinementList: { wot: ['\\-wat', 'wut'] } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'index', - items: [ - { - label: 'wot: ', - attribute: 'wot', - currentRefinement: ['\\-wat', 'wut'], - value: metadata.items[0].value, - items: [ - { - label: '-wat', - value: metadata.items[0].items[0].value, - }, - { - label: 'wut', - value: metadata.items[0].items[1].value, - }, - ], - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', contextValue }, - { refinementList: { one: ['one1', 'one2'], two: ['two'] } } - ); - - let searchState = metadata.items[0].items[0].value({ - refinementList: { one: ['one1', 'one2'], two: ['two'] }, - }); - - expect(searchState).toEqual({ - page: 1, - refinementList: { one: ['one2'], two: ['two'] }, - }); - - searchState = metadata.items[0].items[1].value(searchState); - - expect(searchState).toEqual({ - page: 1, - refinementList: { one: '', two: ['two'] }, - }); - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue }, - { - refinementList: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - refinementList: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue }, - searchState - ); - expect(searchState).toEqual({ - refinementList: {}, - another: { searchState: 'searchState' }, - }); - }); - - it('calling searchForItems return the right searchForItems parameters with limit', () => { - const parameters = connect.searchForFacetValues( - { - attribute: 'ok', - limit: 15, - showMoreLimit: 25, - showMore: false, - contextValue, - }, - {}, - 'yep' - ); - - expect(parameters).toEqual({ - facetName: 'ok', - query: 'yep', - maxFacetHits: 15, - }); - }); - - it('calling searchForItems return the right searchForItems parameters with showMoreLimit', () => { - const parameters = connect.searchForFacetValues( - { - attribute: 'ok', - limit: 15, - showMoreLimit: 25, - showMore: true, - contextValue, - }, - {}, - 'yep' - ); - - expect(parameters).toEqual({ - facetName: 'ok', - query: 'yep', - maxFacetHits: 25, - }); - }); - - it('computes canRefine based on the length of the transformed items list', () => { - const transformItems = () => []; - - props = connect.getProvidedProps( - { attribute: 'ok', transformItems, contextValue }, - {}, - { results } - ); - - expect(props.canRefine).toEqual(false); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - const results = { - first: { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - }, - second: { - getFacetValues: jest.fn(() => []), - getFacetByName: () => true, - }, - }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - {}, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: [], - isFromSearch: false, - canRefine: false, - }); - - props = connect.getProvidedProps( - { attribute: 'ok', contextValue, indexContextValue }, - { indices: { second: { refinementList: { ok: ['wat'] } } } }, - { results } - ); - expect(props).toEqual({ - items: [], - currentRefinement: ['wat'], - isFromSearch: false, - canRefine: false, - }); - - results.second.getFacetValues.mockClear(); - results.second.getFacetValues.mockImplementation(() => [ - { - name: 'wat', - isRefined: true, - count: 20, - }, - { - name: 'oy', - isRefined: false, - count: 10, - }, - ]); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { attribute: 'ok', contextValue, indexContextValue }, - { - otherKey: 'val', - indices: { second: { refinementList: { otherKey: ['val'] } } }, - }, - ['yep'] - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { - second: { - page: 1, - refinementList: { ok: ['yep'], otherKey: ['val'] }, - }, - }, - }); - - nextState = connect.refine( - { - attribute: 'ok', - contextValue, - indexContextValue, - }, - { - otherKey: 'val', - indices: { second: { refinementList: { otherKey: ['val'] } } }, - }, - ['yep'] - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { - second: { - page: 1, - refinementList: { ok: ['yep'], otherKey: ['val'] }, - }, - }, - }); - }); - - it('correctly applies its state to search parameters', () => { - const initSP = new SearchParameters(); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - operator: 'or', - limit: 1, - contextValue, - indexContextValue, - }, - { indices: { second: { refinementList: { ok: ['wat'] } } } } - ); - expect(params).toEqual( - initSP - .addDisjunctiveFacet('ok') - .addDisjunctiveFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - - params = connect.getSearchParameters( - initSP, - { - attribute: 'ok', - operator: 'and', - limit: 1, - contextValue, - indexContextValue, - }, - { indices: { second: { refinementList: { ok: ['wat'] } } } } - ); - expect(params).toEqual( - initSP - .addFacet('ok') - .addFacetRefinement('ok', 'wat') - .setQueryParameter('maxValuesPerFacet', 1) - ); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 'wot', contextValue, indexContextValue }, - { indices: { second: { refinementList: { wot: ['wat', 'wut'] } } } } - ); - expect(metadata).toEqual({ - id: 'wot', - index: 'second', - items: [ - { - label: 'wot: ', - attribute: 'wot', - currentRefinement: ['wat', 'wut'], - value: metadata.items[0].value, - items: [ - { - label: 'wat', - value: metadata.items[0].items[0].value, - }, - { - label: 'wut', - value: metadata.items[0].items[1].value, - }, - ], - // Ignore value, we test it later - }, - ], - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', contextValue, indexContextValue }, - { - indices: { - second: { refinementList: { one: ['one1', 'one2'], two: ['two'] } }, - }, - } - ); - - let searchState = metadata.items[0].items[0].value({ - indices: { - second: { refinementList: { one: ['one1', 'one2'], two: ['two'] } }, - }, - }); - - expect(searchState).toEqual({ - indices: { - second: { page: 1, refinementList: { one: ['one2'], two: ['two'] } }, - }, - }); - - searchState = metadata.items[0].items[1].value(searchState); - - expect(searchState).toEqual({ - indices: { - second: { page: 1, refinementList: { one: '', two: ['two'] } }, - }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue, indexContextValue }, - { - indices: { - second: { - refinementList: { name: 'searchState', name2: 'searchState' }, - }, - }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: { refinementList: { name2: 'searchState' } } }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - indices: { second: { refinementList: {} } }, - another: { searchState: 'searchState' }, - }); - }); - - it('errors if searchable is used in a multi index context', () => { - expect(() => { - connect.getProvidedProps( - { - contextValue, - indexContextValue, - searchable: true, - }, - {}, - {} - ); - }).toThrowErrorMatchingInlineSnapshot( - `"react-instantsearch: searching in *List is not available when used inside a multi index context"` - ); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectRelevantSort.ts b/packages/react-instantsearch-core/src/connectors/__tests__/connectRelevantSort.ts deleted file mode 100644 index ec5bfb5f9d..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectRelevantSort.ts +++ /dev/null @@ -1,229 +0,0 @@ -import connectReal from '../connectRelevantSort'; - -import type { ConnectorDescription } from '../../core/createConnector'; - -jest.mock( - '../../core/createConnector', - () => (connector: ConnectorDescription) => connector -); -// our mock implementation is diverging from the regular createConnector, -// so we redefine it as `any` here, since we have no more information -// @TODO: refactor these tests to work better with TS -const connect: any = connectReal; - -describe('connectRelevantSort', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('returns false when results are null', () => { - const props = connect.getProvidedProps({ contextValue }, null, { - results: null, - }); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: false, - }); - }); - - it('returns correct props with defined appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps({ contextValue }, null, { - results: { - hits: [], - nbHits: 300, - nbSortedHits: 1, - appliedRelevancyStrictness: 30, - }, - }); - - expect(props).toEqual({ - isRelevantSorted: true, - isVirtualReplica: true, - }); - }); - - it('returns correct props with undefined appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps({ contextValue }, null, { - results: {}, - }); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: false, - }); - }); - - it('decide isRelevantSorted based on appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps({ contextValue }, null, { - results: { - hits: [], - appliedRelevancyStrictness: 0, - }, - }); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: true, - }); - }); - - it('apply relevancyStrictness on refine', () => { - let props = connect.getProvidedProps({ contextValue }, null, { - results: { - hits: [], - nbHits: 300, - nbSortedHits: 1, - appliedRelevancyStrictness: 98, - }, - }); - - expect(props).toEqual({ - isRelevantSorted: true, - isVirtualReplica: true, - }); - - const searchState = connect.refine({}, { relevancyStrictness: 98 }, 0); - - expect(searchState).toEqual({ - relevancyStrictness: 0, - page: 1, - }); - - props = connect.getProvidedProps({ contextValue }, searchState, { - results: { - hits: [], - appliedRelevancyStrictness: 0, - }, - }); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: true, - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('returns false when results are null', () => { - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { second: null }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: false, - }); - }); - - it('returns correct props with defined appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: [], - nbHits: 300, - nbSortedHits: 1, - appliedRelevancyStrictness: 30, - }, - }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: true, - isVirtualReplica: true, - }); - }); - - it('returns correct props with undefined appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { second: {} }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: false, - }); - }); - - it('decide isRelevantSorted based on appliedRelevancyStrictness', () => { - const props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: [], - appliedRelevancyStrictness: 0, - }, - }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: true, - }); - }); - - it('apply relevancyStrictness on refine', () => { - let props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { - second: { - hits: [], - nbHits: 300, - nbSortedHits: 1, - appliedRelevancyStrictness: 30, - }, - }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: true, - isVirtualReplica: true, - }); - - const searchState = connect.refine({}, { relevancyStrictness: 98 }, 0); - - expect(searchState).toEqual({ - relevancyStrictness: 0, - page: 1, - }); - - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - searchState, - { - results: { - second: { - hits: [], - appliedRelevancyStrictness: 0, - }, - }, - } - ); - - expect(props).toEqual({ - isRelevantSorted: false, - isVirtualReplica: true, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectScrollTo.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectScrollTo.js deleted file mode 100644 index 4e1f57255a..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectScrollTo.js +++ /dev/null @@ -1,77 +0,0 @@ -import connect from '../connectScrollTo'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -describe('connectScrollTo', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - it('provides the correct props to the component', () => { - const instance = {}; - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue }, - { p: 1, configure: 3, refinementList: 'ok' } - ); - expect(props).toEqual({ value: 1, hasNotChanged: false }); - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue }, - { p: 1, configure: 3, refinementList: 'not ok' } - ); - expect(props).toEqual({ value: 1, hasNotChanged: false }); - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue }, - { p: 2, configure: 3, refinementList: 'not ok' } - ); - expect(props).toEqual({ value: 2, hasNotChanged: true }); - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'anything', contextValue }, - { anything: 2 } - ); - expect(props).toEqual({ value: 2, hasNotChanged: false }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - it('provides the correct props to the component', () => { - const instance = {}; - const searchState = { indices: { second: { p: 1 } } }; - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue, indexContextValue }, - searchState - ); - expect(props).toEqual({ value: 1, hasNotChanged: true }); - - searchState.indices.second = { ...searchState.indices.second, p: 2 }; - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue, indexContextValue }, - searchState - ); - expect(props).toEqual({ value: 2, hasNotChanged: true }); - - searchState.indices.second = { - ...searchState.indices.second, - anything: 'ok', - }; - - props = connect.getProvidedProps.call( - instance, - { scrollOn: 'p', contextValue, indexContextValue }, - searchState - ); - expect(props).toEqual({ value: 2, hasNotChanged: false }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectSearchBox.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectSearchBox.js deleted file mode 100644 index 2d6d35a408..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectSearchBox.js +++ /dev/null @@ -1,155 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectSearchBox'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectSearchBox', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps({ contextValue }, {}, {}); - expect(props).toEqual({ currentRefinement: '' }); - - props = connect.getProvidedProps({ contextValue }, { query: 'yep' }, {}); - expect(props).toEqual({ currentRefinement: 'yep' }); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - query: 'yep', - }); - }); - - it('supports defaultRefinement', () => { - expect( - connect.getProvidedProps( - { defaultRefinement: 'yaw', contextValue }, - {}, - {} - ) - ).toEqual({ - currentRefinement: 'yaw', - }); - }); - - it('refines the query parameter', () => { - params = connect.getSearchParameters( - new SearchParameters(), - { contextValue }, - { query: 'bar' } - ); - expect(params.query).toBe('bar'); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue }, - { - query: { searchState: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ another: { searchState: 'searchState' } }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - {}, - {} - ); - expect(props).toEqual({ currentRefinement: '' }); - - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - { indices: { second: { query: 'yep' } } }, - {} - ); - expect(props).toEqual({ currentRefinement: 'yep' }); - }); - - it("calling refine updates the widget's search state", () => { - let nextState = connect.refine( - { contextValue, indexContextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { second: { query: 'yep', page: 1 } }, - }); - - nextState = connect.refine( - { - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { - indices: { - first: { query: 'yep' }, - }, - otherKey: 'val', - }, - 'yip' - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { - first: { query: 'yip', page: 1 }, - }, - }); - }); - - it('supports defaultRefinement', () => { - expect( - connect.getProvidedProps( - { defaultRefinement: 'yaw', contextValue, indexContextValue }, - {}, - {} - ) - ).toEqual({ - currentRefinement: 'yaw', - }); - }); - - it('refines the query parameter', () => { - params = connect.getSearchParameters( - new SearchParameters(), - { contextValue, indexContextValue }, - { indices: { second: { query: 'bar' } } } - ); - expect(params.query).toBe('bar'); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue, indexContextValue }, - { - indices: { second: { query: '' } }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: {} }, - another: { searchState: 'searchState' }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectSortBy.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectSortBy.js deleted file mode 100644 index 14cb0259bd..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectSortBy.js +++ /dev/null @@ -1,150 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectSortBy'; - -jest.mock('../../core/createConnector', () => (x) => x); - -let props; -let params; - -describe('connectSortBy', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { items: [{ value: 'yep' }, { value: 'yop' }], contextValue }, - { sortBy: 'yep' } - ); - expect(props).toEqual({ - items: [ - { value: 'yep', isRefined: true }, - { value: 'yop', isRefined: false }, - ], - currentRefinement: 'yep', - }); - - props = connect.getProvidedProps( - { items: [{ value: 'yep' }], defaultRefinement: 'yep', contextValue }, - {} - ); - expect(props).toEqual({ - items: [{ value: 'yep', isRefined: true }], - currentRefinement: 'yep', - }); - - const transformItems = jest.fn(() => ['items']); - props = connect.getProvidedProps( - { - items: [{ value: 'yep' }, { value: 'yop' }], - transformItems, - contextValue, - }, - { sortBy: 'yep' } - ); - expect(transformItems.mock.calls[0][0]).toEqual([ - { value: 'yep', isRefined: true }, - { value: 'yop', isRefined: false }, - ]); - expect(props.items).toEqual(['items']); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - page: 1, - sortBy: 'yep', - }); - }); - - it('refines the index parameter', () => { - params = connect.getSearchParameters( - new SearchParameters(), - { contextValue }, - { sortBy: 'yep' } - ); - expect(params.index).toBe('yep'); - }); - - it('registers its id in metadata', () => { - const metadata = connect.getMetadata({ contextValue }); - expect(metadata).toEqual({ id: 'sortBy' }); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { - contextValue, - }, - { - sortBy: { searchState: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ another: { searchState: 'searchState' } }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - props = connect.getProvidedProps( - { - items: [{ value: 'yep' }, { value: 'yop' }], - contextValue, - indexContextValue, - }, - { indices: { second: { sortBy: 'yep' } } } - ); - expect(props).toEqual({ - items: [ - { value: 'yep', isRefined: true }, - { value: 'yop', isRefined: false }, - ], - currentRefinement: 'yep', - }); - }); - - it("calling refine updates the widget's search state", () => { - const nextState = connect.refine( - { contextValue, indexContextValue }, - { otherKey: 'val' }, - 'yep' - ); - expect(nextState).toEqual({ - otherKey: 'val', - indices: { second: { page: 1, sortBy: 'yep' } }, - }); - }); - - it('refines the index parameter', () => { - params = connect.getSearchParameters( - new SearchParameters(), - { contextValue, indexContextValue }, - { indices: { second: { sortBy: 'yep' } } } - ); - expect(params.index).toBe('yep'); - }); - - it('should return the right searchState when clean up', () => { - const searchState = connect.cleanUp( - { contextValue, indexContextValue }, - { - indices: { second: { sortBy: { searchState: 'searchState' } } }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: {} }, - another: { searchState: 'searchState' }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectStateResults.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectStateResults.js deleted file mode 100644 index 039aa85400..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectStateResults.js +++ /dev/null @@ -1,85 +0,0 @@ -import connect from '../connectStateResults'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectStateResults', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - const searchState = { state: 'state' }; - const error = 'error'; - const searching = true; - const isSearchStalled = true; - const searchingForFacetValues = true; - const searchResults = { - results: { nbHits: 25, hits: [] }, - error, - searching, - isSearchStalled, - searchingForFacetValues, - }; - - const expectation = { - searchState, - searchResults: searchResults.results, - allSearchResults: searchResults.results, - props: { props: 'props', contextValue }, - error, - searching, - isSearchStalled, - searchingForFacetValues, - }; - - const actual = connect.getProvidedProps( - { props: 'props', contextValue }, - searchState, - searchResults - ); - - expect(actual).toEqual(expectation); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - const searchState = { state: 'state' }; - const error = 'error'; - const searching = true; - const isSearchStalled = true; - const searchingForFacetValues = true; - const searchResults = { - results: { - first: { nbHits: 25, hits: [] }, - second: { nbHits: 26, hits: [] }, - }, - error, - searching, - isSearchStalled, - searchingForFacetValues, - }; - - const expectation = { - searchState, - searchResults: searchResults.results.second, - allSearchResults: searchResults.results, - props: { props: 'props', contextValue, indexContextValue }, - error, - searching, - isSearchStalled, - searchingForFacetValues, - }; - - const actual = connect.getProvidedProps( - { props: 'props', contextValue, indexContextValue }, - searchState, - searchResults - ); - - expect(actual).toEqual(expectation); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectStats.ts b/packages/react-instantsearch-core/src/connectors/__tests__/connectStats.ts deleted file mode 100644 index c2d7a0b3bc..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectStats.ts +++ /dev/null @@ -1,74 +0,0 @@ -import connectReal from '../connectStats'; - -import type { ConnectorDescription } from '../../core/createConnector'; - -jest.mock( - '../../core/createConnector', - () => (connector: ConnectorDescription) => connector -); -// our mock implementation is diverging from the regular createConnector, -// so we redefine it as `any` here, since we have no more information -// @TODO: refactor these tests to work better with TS -const connect: any = connectReal; - -describe('connectStats', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - it('provides the correct props to the component', () => { - let props = connect.getProvidedProps({ contextValue }, null, {}); - expect(props).toBe(null); - - props = connect.getProvidedProps({ contextValue }, null, { - results: { - nbHits: 666, - processingTimeMS: 1, - hits: [], - nbSortedHits: undefined, - isRelevantSorted: false, - }, - }); - expect(props).toEqual({ - nbHits: 666, - processingTimeMS: 1, - nbSortedHits: undefined, - areHitsSorted: false, - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - it('provides the correct props to the component', () => { - let props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - {} - ); - expect(props).toBe(null); - - props = connect.getProvidedProps( - { contextValue, indexContextValue }, - null, - { - results: { - second: { - nbHits: 666, - processingTimeMS: 1, - nbSortedHits: undefined, - isRelevantSorted: false, - }, - }, - } - ); - expect(props).toEqual({ - nbHits: 666, - processingTimeMS: 1, - nbSortedHits: undefined, - areHitsSorted: false, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectToggleRefinement.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectToggleRefinement.js deleted file mode 100644 index 83cf730020..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectToggleRefinement.js +++ /dev/null @@ -1,933 +0,0 @@ -import { SearchParameters, SearchResults } from 'algoliasearch-helper'; - -import connect from '../connectToggleRefinement'; - -jest.mock('../../core/createConnector', () => (x) => x); - -const createSearchResults = ({ disjunctiveFacets, facets }) => - new SearchResults( - new SearchParameters({ - disjunctiveFacets, - }), - [ - { - facets, - hits: [ - { objectID: '0123', name: 'Apple' }, - { objectID: '0123', name: 'Samsung' }, - { objectID: '0123', name: 'Microsoft' }, - ], - }, - ] - ); - -describe('connectToggleRefinement', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - const createSingleIndexSearchResults = (...args) => ({ - results: createSearchResults(...args), - }); - - it('expect `currentRefinement` to be `true` when the value is checked', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = { toggle: { shipping: true } }; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(true); - }); - - it('expect `currentRefinement` to be `false` when the value is not checked', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(false); - }); - - it('expect `currentRefinement` to be `false` when searchState is a string considered falsy', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = { toggle: { shipping: 'false' } }; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(false); - }); - - it('expect `currentRefinement` to be `defaultRefinement`', () => { - const props = { - defaultRefinement: true, - attribute: 'shipping', - value: true, - contextValue, - }; - const searchState = {}; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(true); - }); - - it('expect `canRefine` to be computed to `true` from all the facet values when the value is checked', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = { toggle: { shipping: true } }; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 100, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(true); - }); - - it('expect `canRefine` to be computed to `true` from the selected facet value when the value is not checked', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 50, - false: 100, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(true); - }); - - it('expect `canRefine` to be `false` with a value count of 0', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 0, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without the facet values', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without the facet', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: [], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without results', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `count` to match facet values with results', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 100, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: 150, - unchecked: 100, - }); - }); - - it('expect `count` to be null without the facet', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = createSingleIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: null, - unchecked: null, - }); - }); - - it('expect `count` to be null without results', () => { - const props = { attribute: 'shipping', value: true, contextValue }; - const searchState = {}; - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: null, - unchecked: null, - }); - }); - - it("calling refine updates the widget's search state", () => { - let searchState = connect.refine( - { attribute: 't', contextValue }, - { otherKey: 'val', toggle: { otherKey: false } }, - true - ); - expect(searchState).toEqual({ - otherKey: 'val', - page: 1, - toggle: { t: true, otherKey: false }, - }); - - searchState = connect.refine( - { attribute: 't', contextValue }, - { otherKey: 'val' }, - false - ); - expect(searchState).toEqual({ - page: 1, - otherKey: 'val', - toggle: { t: false }, - }); - }); - - it('refines the corresponding facet with `true`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - value: 'val', - contextValue, - }, - { - toggle: { - facet: true, - }, - } - ); - - expect(params.getDisjunctiveRefinements('facet')).toEqual(['val']); - }); - - it('does not refine the corresponding facet with `false`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - value: 'val', - contextValue, - }, - { - toggle: { - facet: false, - }, - } - ); - - expect(params.getDisjunctiveRefinements('facet')).toEqual([]); - }); - - it('applies the provided filter with `true`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - filter: (sp) => sp.setQuery('yep'), - contextValue, - }, - { - toggle: { - facet: true, - }, - } - ); - - expect(params.query).toEqual('yep'); - }); - - it('does not apply the provided filter with `false`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - filter: (sp) => sp.setQuery('yep'), - contextValue, - }, - { - toggle: { - facet: false, - }, - } - ); - - expect(params.query).toBeUndefined(); - }); - - it('registers its filter in metadata', () => { - let metadata = connect.getMetadata({ attribute: 't', contextValue }, {}); - expect(metadata).toEqual({ - items: [], - id: 't', - index: 'index', - }); - - metadata = connect.getMetadata( - { attribute: 't', label: 'yep', contextValue }, - { toggle: { t: true } } - ); - expect(metadata).toEqual({ - items: [ - { - label: 'yep', - // Ignore clear, we test it later - value: metadata.items[0].value, - attribute: 't', - currentRefinement: true, - }, - ], - id: 't', - index: 'index', - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', label: 'yep', contextValue }, - { toggle: { one: true, two: false } } - ); - - const searchState = metadata.items[0].value({ - toggle: { one: true, two: false }, - }); - - expect(searchState).toEqual({ - page: 1, - toggle: { one: false, two: false }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue }, - { - toggle: { name: 'searchState', name2: 'searchState' }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - toggle: { name2: 'searchState' }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue }, - searchState - ); - expect(searchState).toEqual({ - toggle: {}, - another: { searchState: 'searchState' }, - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - const createMultiIndexSearchState = (state = {}) => ({ - indices: { - second: state, - }, - }); - - const createMultiIndexSearchResults = (...args) => ({ - results: { - second: createSearchResults(...args), - }, - }); - - it('expect `currentRefinement` to be `true` when the value is checked', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState({ - toggle: { shipping: true }, - }); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(true); - }); - - it('expect `currentRefinement` to be `false` when the value is not checked', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(false); - }); - - it('expect `currentRefinement` to be `false` when searchState is a string considered falsy', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState({ - toggle: { shipping: 'false' }, - }); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(false); - }); - - it('expect `currentRefinement` to be `defaultRefinement`', () => { - const props = { - defaultRefinement: true, - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.currentRefinement).toBe(true); - }); - - it('expect `canRefine` to be computed to `true` from all the facet values when the value is checked', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState({ - toggle: { shipping: true }, - }); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 100, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(true); - }); - - it('expect `canRefine` to be computed to `true` from the selected facet value when the value is not checked', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 50, - false: 100, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(true); - }); - - it('expect `canRefine` to be `false` with a value count of 0', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 0, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without the facet values', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without the facet', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: [], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `canRefine` to be `false` without results', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.canRefine).toBe(false); - }); - - it('expect `count` to match facet values with results', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: { - shipping: { - true: 100, - false: 50, - }, - }, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: 150, - unchecked: 100, - }); - }); - - it('expect `count` to be null without the facet', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = createMultiIndexSearchResults({ - disjunctiveFacets: ['shipping'], - facets: {}, - }); - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: null, - unchecked: null, - }); - }); - - it('expect `count` to be null without results', () => { - const props = { - attribute: 'shipping', - value: true, - contextValue, - indexContextValue, - }; - const searchState = createMultiIndexSearchState(); - const searchResults = {}; - - const actual = connect.getProvidedProps( - props, - searchState, - searchResults - ); - - expect(actual.count).toEqual({ - checked: null, - unchecked: null, - }); - }); - - it("calling refine updates the widget's search state", () => { - let searchState = connect.refine( - { attribute: 't', contextValue, indexContextValue }, - { - otherKey: 'val', - indices: { second: { toggle: { otherKey: false } } }, - }, - true - ); - expect(searchState).toEqual({ - otherKey: 'val', - indices: { second: { page: 1, toggle: { t: true, otherKey: false } } }, - }); - - searchState = connect.refine( - { - attribute: 't', - contextValue: { mainTargetedIndex: 'first' }, - indexContextValue: { targetedIndex: 'first' }, - }, - { indices: { first: { toggle: { t: true, otherKey: false } } } }, - false - ); - expect(searchState).toEqual({ - indices: { - first: { page: 1, toggle: { t: false, otherKey: false } }, - }, - }); - }); - - it('refines the corresponding facet with `true`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - value: 'val', - contextValue, - indexContextValue, - }, - { - indices: { - second: { - toggle: { - facet: true, - }, - }, - }, - } - ); - - expect(params.getDisjunctiveRefinements('facet')).toEqual(['val']); - }); - - it('does not refine the corresponding facet with `false`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - value: 'val', - contextValue, - indexContextValue, - }, - { - indices: { - second: { - toggle: { - facet: false, - }, - }, - }, - } - ); - - expect(params.getDisjunctiveRefinements('facet')).toEqual([]); - }); - - it('applies the provided filter with `true`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - filter: (sp) => sp.setQuery('yep'), - contextValue, - indexContextValue, - }, - { - indices: { - second: { - toggle: { - facet: true, - }, - }, - }, - } - ); - - expect(params.query).toEqual('yep'); - }); - - it('does not apply the provided filter with `false`', () => { - const params = connect.getSearchParameters( - new SearchParameters(), - { - attribute: 'facet', - filter: (sp) => sp.setQuery('yep'), - contextValue, - indexContextValue, - }, - { - indices: { - second: { - toggle: { - facet: false, - }, - }, - }, - } - ); - - expect(params.query).toBeUndefined(); - }); - - it('registers its filter in metadata', () => { - const metadata = connect.getMetadata( - { attribute: 't', label: 'yep', contextValue, indexContextValue }, - { indices: { second: { toggle: { t: true } } } } - ); - expect(metadata).toEqual({ - items: [ - { - label: 'yep', - // Ignore clear, we test it later - value: metadata.items[0].value, - attribute: 't', - currentRefinement: true, - }, - ], - id: 't', - index: 'second', - }); - }); - - it('items value function should clear it from the search state', () => { - const metadata = connect.getMetadata( - { attribute: 'one', label: 'yep', contextValue, indexContextValue }, - { indices: { second: { toggle: { one: true, two: false } } } } - ); - - const searchState = metadata.items[0].value({ - indices: { second: { toggle: { one: true, two: false } } }, - }); - - expect(searchState).toEqual({ - indices: { second: { page: 1, toggle: { one: false, two: false } } }, - }); - }); - - it('should return the right searchState when clean up', () => { - let searchState = connect.cleanUp( - { attribute: 'name', contextValue, indexContextValue }, - { - indices: { - second: { toggle: { name: 'searchState', name2: 'searchState' } }, - }, - another: { searchState: 'searchState' }, - } - ); - expect(searchState).toEqual({ - indices: { second: { toggle: { name2: 'searchState' } } }, - another: { searchState: 'searchState' }, - }); - - searchState = connect.cleanUp( - { attribute: 'name2', contextValue, indexContextValue }, - searchState - ); - expect(searchState).toEqual({ - indices: { second: { toggle: {} } }, - another: { searchState: 'searchState' }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/connectors/__tests__/connectVoiceSearch.js b/packages/react-instantsearch-core/src/connectors/__tests__/connectVoiceSearch.js deleted file mode 100644 index 087febfbd2..0000000000 --- a/packages/react-instantsearch-core/src/connectors/__tests__/connectVoiceSearch.js +++ /dev/null @@ -1,350 +0,0 @@ -import { SearchParameters } from 'algoliasearch-helper'; - -import connect from '../connectVoiceSearch'; - -jest.mock('../../core/createConnector', () => (x) => x); - -describe('connectVoiceSearch', () => { - describe('single index', () => { - const contextValue = { mainTargetedIndex: 'index' }; - - describe('getProvidedProps', () => { - it('provides the correct props to the component', () => { - expect(connect.getProvidedProps({ contextValue }, {}, {})).toEqual({ - currentRefinement: '', - }); - - expect( - connect.getProvidedProps({ contextValue }, { query: 'abc' }, {}) - ).toEqual({ - currentRefinement: 'abc', - }); - }); - }); - - describe('refine', () => { - it('calls refine and updates the state correctly', () => { - expect(connect.refine({ contextValue }, {}, 'abc')).toEqual({ - page: 1, - query: 'abc', - additionalVoiceParameters: {}, - }); - }); - - it('refines and get additionalVoiceParameters', () => { - const { additionalVoiceParameters } = connect.refine( - { contextValue }, - {}, - 'abc' - ); - expect(additionalVoiceParameters).toEqual(expect.objectContaining({})); - }); - - it('refines with additionalQueryParameters', () => { - const props = { - contextValue, - additionalQueryParameters: () => ({ additional: 'param' }), - }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - page: 1, - query: 'abc', - additionalVoiceParameters: { - additional: 'param', - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: undefined, - removeStopWords: true, - }, - }); - }); - - it('refines with language', () => { - const props = { contextValue, language: 'en-US' }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - page: 1, - query: 'abc', - additionalVoiceParameters: { - queryLanguages: ['en'], - }, - }); - }); - - it('refines with language (2)', () => { - const props = { - contextValue, - language: 'en-US', - additionalQueryParameters: () => ({}), - }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - page: 1, - query: 'abc', - additionalVoiceParameters: { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - }, - }); - }); - - it('overrides with additionalQueryParameters', () => { - const props = { - contextValue, - additionalQueryParameters: () => ({ - ignorePlurals: false, - optionalWords: 'something else', - removeStopWords: false, - }), - }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - page: 1, - query: 'abc', - additionalVoiceParameters: { - ignorePlurals: false, - optionalWords: 'something else', - removeStopWords: false, - }, - }); - }); - }); - - describe('cleanUp', () => { - it('should return the right searchState when clean up', () => { - expect( - connect.cleanUp( - { - contextValue, - }, - { - query: 'abc', - additionalVoiceParameters: { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - }, - } - ) - ).toEqual({}); - }); - }); - - describe('getSearchParameters', () => { - it('returns searchParameters with query', () => { - expect( - connect.getSearchParameters( - new SearchParameters(), - { - contextValue, - }, - { query: 'foo' } - ) - ).toEqual(expect.objectContaining({ query: 'foo' })); - }); - - it('returns searchParameters with additional params', () => { - expect( - connect.getSearchParameters( - new SearchParameters(), - { - contextValue, - }, - { - query: 'abc', - additionalVoiceParameters: { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - }, - } - ) - ).toEqual( - expect.objectContaining({ - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - query: 'abc', - }) - ); - }); - }); - - describe('getMetadata', () => { - it('returns correct metadata', () => { - expect( - connect.getMetadata( - { - contextValue, - }, - { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - query: 'abc', - } - ) - ).toEqual({ - id: 'query', - index: 'index', - items: [ - { - label: 'query: abc', - value: expect.any(Function), - currentRefinement: 'abc', - }, - ], - }); - }); - }); - }); - - describe('multi index', () => { - const contextValue = { mainTargetedIndex: 'first' }; - const indexContextValue = { targetedIndex: 'second' }; - - describe('getProvidedProps', () => { - it('provides the correct props to the component', () => { - expect( - connect.getProvidedProps({ contextValue, indexContextValue }, {}, {}) - ).toEqual({ - currentRefinement: '', - }); - - expect( - connect.getProvidedProps( - { contextValue, indexContextValue }, - { indices: { second: { query: 'yep' } } }, - {} - ) - ).toEqual({ - currentRefinement: 'yep', - }); - }); - }); - - describe('refine', () => { - it('refines with additionalQueryParameters', () => { - const props = { - contextValue, - indexContextValue, - additionalQueryParameters: () => ({ additional: 'param' }), - }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - indices: { - second: { - page: 1, - query: 'abc', - additionalVoiceParameters: { - additional: 'param', - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: undefined, - removeStopWords: true, - }, - }, - }, - }); - }); - - it('refines with language', () => { - const props = { contextValue, indexContextValue, language: 'en-US' }; - expect(connect.refine(props, {}, 'abc')).toEqual({ - indices: { - second: { - page: 1, - query: 'abc', - additionalVoiceParameters: { - queryLanguages: ['en'], - }, - }, - }, - }); - }); - }); - - describe('getSearchParameters', () => { - it('returns searchParameters with query', () => { - expect( - connect.getSearchParameters( - new SearchParameters(), - { - contextValue, - indexContextValue, - }, - { indices: { second: { query: 'foo' } } } - ) - ).toEqual(expect.objectContaining({ query: 'foo' })); - }); - - it('returns searchParameters with additional params', () => { - expect( - connect.getSearchParameters( - new SearchParameters(), - { - contextValue, - indexContextValue, - }, - { - indices: { - second: { - query: 'abc', - additionalVoiceParameters: { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - }, - }, - }, - } - ) - ).toEqual( - expect.objectContaining({ - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - query: 'abc', - }) - ); - }); - }); - - describe('getMetadata', () => { - it('returns correct metadata', () => { - expect( - connect.getMetadata( - { - contextValue, - indexContextValue, - }, - { - indices: { - second: { - ignorePlurals: true, - optionalWords: 'abc', - queryLanguages: ['en'], - removeStopWords: true, - query: 'abc', - }, - }, - } - ) - ).toEqual({ - id: 'query', - index: 'second', - items: [ - { - label: 'query: abc', - value: expect.any(Function), - currentRefinement: 'abc', - }, - ], - }); - }); - }); - }); -}); diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useBreadcrumb.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useBreadcrumb.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useBreadcrumb.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useBreadcrumb.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useClearRefinements.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useClearRefinements.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useClearRefinements.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useClearRefinements.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useConfigure.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useConfigure.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useConfigure.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useConfigure.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useCurrentRefinements.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useCurrentRefinements.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useCurrentRefinements.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useCurrentRefinements.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useDynamicWidgets.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useDynamicWidgets.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useDynamicWidgets.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useDynamicWidgets.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useGeoSearch.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useGeoSearch.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useGeoSearch.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useGeoSearch.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useHierarchicalMenu.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useHierarchicalMenu.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useHierarchicalMenu.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useHierarchicalMenu.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useHits.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useHits.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useHits.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useHits.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useHitsPerPage.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useHitsPerPage.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useHitsPerPage.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useHitsPerPage.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useInfiniteHits.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useInfiniteHits.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useInfiniteHits.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useInfiniteHits.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useMenu.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useMenu.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useMenu.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useMenu.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useNumericMenu.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useNumericMenu.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useNumericMenu.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useNumericMenu.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/usePagination.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/usePagination.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/usePagination.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/usePagination.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/usePoweredBy.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/usePoweredBy.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/usePoweredBy.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/usePoweredBy.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useQueryRules.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useQueryRules.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useQueryRules.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useQueryRules.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useRange.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useRange.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useRange.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useRange.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useRefinementList.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useRefinementList.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useRefinementList.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useRefinementList.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useSearchBox.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useSearchBox.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useSearchBox.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useSearchBox.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useSortBy.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useSortBy.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useSortBy.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useSortBy.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useStats.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useStats.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useStats.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useStats.test.tsx diff --git a/packages/react-instantsearch-hooks/src/connectors/__tests__/useToggleRefinement.test.tsx b/packages/react-instantsearch-core/src/connectors/__tests__/useToggleRefinement.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/__tests__/useToggleRefinement.test.tsx rename to packages/react-instantsearch-core/src/connectors/__tests__/useToggleRefinement.test.tsx diff --git a/packages/react-instantsearch-core/src/connectors/connectAutoComplete.js b/packages/react-instantsearch-core/src/connectors/connectAutoComplete.js deleted file mode 100644 index a1ce148706..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectAutoComplete.js +++ /dev/null @@ -1,124 +0,0 @@ -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, -} from '../core/indexUtils'; -import { addQueryID, addAbsolutePositions } from '../core/utils'; - -const getId = () => 'query'; - -function getCurrentRefinement(props, searchState, context) { - const id = getId(); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - '' - ); - - if (currentRefinement) { - return currentRefinement; - } - return ''; -} - -function getHits(searchResults) { - if (searchResults.results) { - if ( - searchResults.results.hits && - Array.isArray(searchResults.results.hits) - ) { - return addAbsolutePositions( - addQueryID(searchResults.results.hits, searchResults.results.queryID), - searchResults.results.hitsPerPage, - searchResults.results.page - ); - } else { - return Object.keys(searchResults.results).reduce( - (hits, index) => [ - ...hits, - { - index, - hits: addAbsolutePositions( - addQueryID( - searchResults.results[index].hits, - searchResults.results[index].queryID - ), - searchResults.results[index].hitsPerPage, - searchResults.results[index].page - ), - }, - ], - [] - ); - } - } else { - return []; - } -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(); - const nextValue = { [id]: nextRefinement }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, getId()); -} - -/** - * connectAutoComplete connector provides the logic to create connected - * components that will render the results retrieved from - * Algolia. - * - * To configure the number of hits retrieved, use [HitsPerPage widget](widgets/HitsPerPage.html), - * [connectHitsPerPage connector](connectors/connectHitsPerPage.html) or pass the hitsPerPage - * prop to a [Configure](guide/Search_parameters.html) widget. - * @name connectAutoComplete - * @kind connector - * @propType {string} [defaultRefinement] - Provide a default value for the query - * @providedPropType {array.} hits - the records that matched the search state - * @providedPropType {function} refine - a function to change the query - * @providedPropType {string} currentRefinement - the query to search for - */ -export default createConnector({ - displayName: 'AlgoliaAutoComplete', - $$type: 'ais.autoComplete', - - getProvidedProps(props, searchState, searchResults) { - return { - hits: getHits(searchResults), - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setQuery( - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectBreadcrumb.js b/packages/react-instantsearch-core/src/connectors/connectBreadcrumb.js deleted file mode 100644 index e83422c8d8..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectBreadcrumb.js +++ /dev/null @@ -1,130 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { refineValue, getResults } from '../core/indexUtils'; - -export const getId = (props) => props.attributes[0]; - -const namespace = 'hierarchicalMenu'; - -function refine(props, searchState, nextRefinement, context) { - const id = getId(props); - const nextValue = { [id]: nextRefinement || '' }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function transformValue(values) { - return values.reduce((acc, item) => { - if (item.isRefined) { - acc.push({ - label: item.name, - // If dealing with a nested "items", "value" is equal to the previous value concatenated with the current value - // If dealing with the first level, "value" is equal to the current value - value: item.escapedValue, - }); - // Create a variable in order to keep the same acc for the recursion, otherwise "reduce" returns a new one - if (item.data) { - acc = acc.concat(transformValue(item.data, acc)); - } - } - return acc; - }, []); -} - -/** - * The breadcrumb component is s a type of secondary navigation scheme that - * reveals the user’s location in a website or web application. - * - * @name connectBreadcrumb - * @requirements To use this widget, your attributes must be formatted in a specific way. - * If you want for example to have a Breadcrumb of categories, objects in your index - * should be formatted this way: - * - * ```json - * { - * "categories.lvl0": "products", - * "categories.lvl1": "products > fruits", - * "categories.lvl2": "products > fruits > citrus" - * } - * ``` - * - * It's also possible to provide more than one path for each level: - * - * ```json - * { - * "categories.lvl0": ["products", "goods"], - * "categories.lvl1": ["products > fruits", "goods > to eat"] - * } - * ``` - * - * All attributes passed to the `attributes` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * - * @kind connector - * @propType {array.} attributes - List of attributes to use to generate the hierarchy of the menu. See the example for the convention to follow. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to toggle a refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {array.<{items: object, count: number, isRefined: boolean, label: string, value: string}>} items - the list of items the Breadcrumb can display. - */ - -export default createConnector({ - displayName: 'AlgoliaBreadcrumb', - $$type: 'ais.breadcrumb', - - propTypes: { - attributes: (props, propName, componentName) => { - const isNotString = (val) => typeof val !== 'string'; - if ( - !Array.isArray(props[propName]) || - props[propName].some(isNotString) || - props[propName].length < 1 - ) { - return new Error( - `Invalid prop ${propName} supplied to ${componentName}. Expected an Array of Strings` - ); - } - return undefined; - }, - transformItems: PropTypes.func, - }, - - getProvidedProps(props, searchState, searchResults) { - const id = getId(props); - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const isFacetPresent = - Boolean(results) && Boolean(results.getFacetByName(id)); - - if (!isFacetPresent) { - return { - items: [], - canRefine: false, - }; - } - - const values = results.getFacetValues(id); - - const items = values.data ? transformValue(values.data) : []; - - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - - return { - canRefine: transformedItems.length > 0, - items: transformedItems, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectConfigure.js b/packages/react-instantsearch-core/src/connectors/connectConfigure.js deleted file mode 100644 index ad6cc410de..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectConfigure.js +++ /dev/null @@ -1,71 +0,0 @@ -import createConnector from '../core/createConnector'; -import { - refineValue, - getIndexId, - hasMultipleIndices, -} from '../core/indexUtils'; -import { omit } from '../core/utils'; - -function getId() { - return 'configure'; -} - -export default createConnector({ - displayName: 'AlgoliaConfigure', - $$type: 'ais.configure', - getProvidedProps() { - return {}; - }, - getSearchParameters(searchParameters, props) { - const { children, contextValue, indexContextValue, ...items } = props; - return searchParameters.setQueryParameters(items); - }, - transitionState(props, prevSearchState, nextSearchState) { - const id = getId(); - const { children, contextValue, indexContextValue, ...items } = props; - const propKeys = Object.keys(props); - const nonPresentKeys = this._props - ? Object.keys(this._props).filter((prop) => propKeys.indexOf(prop) === -1) - : []; - this._props = props; - const nextValue = { - [id]: { ...omit(nextSearchState[id], nonPresentKeys), ...items }, - }; - return refineValue(nextSearchState, nextValue, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - cleanUp(props, searchState) { - const id = getId(); - const indexId = getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const subState = - hasMultipleIndices({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) && searchState.indices - ? searchState.indices[indexId] - : searchState; - - const configureKeys = - subState && subState[id] ? Object.keys(subState[id]) : []; - - const configureState = configureKeys.reduce((acc, item) => { - if (!props[item]) { - acc[item] = subState[id][item]; - } - return acc; - }, {}); - - const nextValue = { [id]: configureState }; - - return refineValue(searchState, nextValue, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectConfigureRelatedItems.ts b/packages/react-instantsearch-core/src/connectors/connectConfigureRelatedItems.ts deleted file mode 100644 index 7ec8156066..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectConfigureRelatedItems.ts +++ /dev/null @@ -1,233 +0,0 @@ -import algoliasearchHelper from 'algoliasearch-helper'; - -import createConnector from '../core/createConnector'; -import { - refineValue, - getIndexId, - hasMultipleIndices, - // @ts-ignore -} from '../core/indexUtils'; -import { - omit, - getObjectType, - getPropertyByPath, - removeEmptyKey, - removeEmptyArraysFromObject, -} from '../core/utils'; - -import type { ConnectedProps } from '../core/createConnector'; -import type { - PlainSearchParameters, - SearchParameters, -} from 'algoliasearch-helper'; - -type Hit = any; - -export type MatchingPatterns = { - [attribute: string]: { - /** - * The score of the optional filter. - * - * @see https://www.algolia.com/doc/guides/managing-results/rules/merchandising-and-promoting/in-depth/optional-filters/ - */ - score: number; - }; -}; - -interface ConfigureRelatedItemsProps { - /** - * The reference hit to extract the filters from. - */ - hit: Hit; - /** - * The schema to create the optional filters. - * Each key represents an attribute from the hit. - */ - matchingPatterns: MatchingPatterns; - /** - * Function to transform the generated search parameters. - */ - transformSearchParameters?: ( - searchParameters: SearchParameters - ) => PlainSearchParameters; -} - -function createOptionalFilter({ - attributeName, - attributeValue, - attributeScore, -}: { - attributeName: string; - attributeValue: string; - attributeScore: number; -}) { - return `${attributeName}:${attributeValue}`; -} - -const defaultProps: Partial = { - transformSearchParameters: (x) => ({ ...x }), -}; - -function getId(): string { - // We store the search state of this widget in `configure`. - return 'configure'; -} - -type InternalConfigureRelatedItemsProps = ConfigureRelatedItemsProps & - Required; - -function getSearchParametersFromProps( - props: ConnectedProps -): PlainSearchParameters { - const optionalFilters = Object.keys(props.matchingPatterns).reduce< - Array - >((acc, attributeName) => { - const attributePattern = props.matchingPatterns[attributeName]; - const attributeValue = getPropertyByPath(props.hit, attributeName); - const attributeScore = attributePattern.score; - - if (Array.isArray(attributeValue)) { - return [ - ...acc, - attributeValue.map((attributeSubValue) => { - return createOptionalFilter({ - attributeName, - attributeValue: attributeSubValue, - attributeScore, - }); - }), - ]; - } - - if (typeof attributeValue === 'string') { - return [ - ...acc, - createOptionalFilter({ - attributeName, - attributeValue, - attributeScore, - }), - ]; - } - - if (process.env.NODE_ENV === 'development') { - // eslint-disable-next-line no-console - console.warn( - `The \`matchingPatterns\` option returned a value of type ${getObjectType( - attributeValue - )} for the "${attributeName}" key. This value was not sent to Algolia because \`optionalFilters\` only supports strings and array of strings. - -You can remove the "${attributeName}" key from the \`matchingPatterns\` option. - -See https://www.algolia.com/doc/api-reference/api-parameters/optionalFilters/` - ); - } - - return acc; - }, []); - - return props.transformSearchParameters( - new algoliasearchHelper.SearchParameters({ - // @ts-ignore @TODO algoliasearch-helper@3.0.1 will contain the type - // `sumOrFiltersScores`. - // See https://github.com/algolia/algoliasearch-helper-js/pull/753 - sumOrFiltersScores: true, - facetFilters: [`objectID:-${props.hit.objectID}`], - optionalFilters, - }) - ); -} - -interface ConnectorState { - _searchParameters: PlainSearchParameters; -} - -export default createConnector({ - displayName: 'AlgoliaConfigureRelatedItems', - $$type: 'ais.configureRelatedItems', - - defaultProps, - - getProvidedProps() { - return {}; - }, - - getSearchParameters( - searchParameters: SearchParameters, - props: ConnectedProps - ) { - return searchParameters.setQueryParameters( - getSearchParametersFromProps(props) - ); - }, - - transitionState( - this: ConnectorState, - props, - _prevSearchState, - nextSearchState - ) { - const id = getId(); - // We need to transform the exhaustive search parameters back to clean - // search parameters without the empty default keys so we don't pollute the - // `configure` search state. - const searchParameters = removeEmptyArraysFromObject( - removeEmptyKey(getSearchParametersFromProps(props)) - ); - - const searchParametersKeys = Object.keys(searchParameters); - const nonPresentKeys = this._searchParameters - ? Object.keys(this._searchParameters).filter( - (prop) => searchParametersKeys.indexOf(prop) === -1 - ) - : []; - this._searchParameters = searchParameters; - const nextValue: any = { - [id]: { - ...omit(nextSearchState[id], nonPresentKeys), - ...searchParameters, - }, - }; - - return refineValue(nextSearchState, nextValue, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(this: ConnectorState, props, searchState) { - const id = getId(); - const indexId = getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const subState = - hasMultipleIndices({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) && searchState.indices - ? searchState.indices[indexId] - : searchState; - - const configureKeys = - subState && subState[id] ? Object.keys(subState[id]) : []; - - const configureState = ( - configureKeys as Array - ).reduce((acc, item) => { - if (!this._searchParameters[item]) { - (acc as any)[item] = subState[id][item]; - } - - return acc; - }, {} as PlainSearchParameters); - - const nextValue = { [id]: configureState }; - - return refineValue(searchState, nextValue, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectCurrentRefinements.js b/packages/react-instantsearch-core/src/connectors/connectCurrentRefinements.js deleted file mode 100644 index 40f1e0d86d..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectCurrentRefinements.js +++ /dev/null @@ -1,66 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; - -/** - * connectCurrentRefinements connector provides the logic to build a widget that will - * give the user the ability to remove all or some of the filters that were - * set. - * @name connectCurrentRefinements - * @kind connector - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @propType {function} [clearsQuery=false] - Pass true to also clear the search query - * @providedPropType {function} refine - a function to remove a single filter - * @providedPropType {array.<{label: string, attribute: string, currentRefinement: string || object, items: array, value: function}>} items - all the filters, the `value` is to pass to the `refine` function for removing all currentrefinements, `label` is for the display. When existing several refinements for the same atribute name, then you get a nested `items` object that contains a `label` and a `value` function to use to remove a single filter. `attribute` and `currentRefinement` are metadata containing row values. - * @providedPropType {string} query - the search query - */ -export default createConnector({ - displayName: 'AlgoliaCurrentRefinements', - $$type: 'ais.currentRefinements', - - propTypes: { - transformItems: PropTypes.func, - }, - - getProvidedProps(props, searchState, searchResults, metadata) { - const items = metadata.reduce((res, meta) => { - if (typeof meta.items !== 'undefined') { - if (!props.clearsQuery && meta.id === 'query') { - return res; - } else { - if ( - props.clearsQuery && - meta.id === 'query' && - meta.items[0].currentRefinement === '' - ) { - return res; - } - return res.concat( - meta.items.map((item) => ({ - ...item, - id: meta.id, - index: meta.index, - })) - ); - } - } - return res; - }, []); - - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - - return { - items: transformedItems, - canRefine: transformedItems.length > 0, - }; - }, - - refine(props, searchState, items) { - // `value` corresponds to our internal clear function computed in each connector metadata. - const refinementsToClear = - items instanceof Array ? items.map((item) => item.value) : [items]; - return refinementsToClear.reduce((res, clear) => clear(res), searchState); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectDynamicWidgets.ts b/packages/react-instantsearch-core/src/connectors/connectDynamicWidgets.ts deleted file mode 100644 index b908e54b38..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectDynamicWidgets.ts +++ /dev/null @@ -1,90 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -// @ts-ignore -import { getResults } from '../core/indexUtils'; - -import type { SearchParameters } from 'algoliasearch-helper'; - -const MAX_WILDCARD_FACETS = 20; - -export default createConnector({ - displayName: 'AlgoliaDynamicWidgets', - $$type: 'ais.dynamicWidgets', - - defaultProps: { - transformItems: (items: any[]) => items, - maxValuesPerFacet: 20, - }, - - propTypes: { - transformItems: PropTypes.func, - facets: PropTypes.arrayOf(PropTypes.string), - maxValuesPerFacet: PropTypes.number, - }, - - getProvidedProps(props, _searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if ( - props.facets && - !( - Array.isArray(props.facets) && - props.facets.length <= 1 && - (props.facets[0] === '*' || props.facets[0] === undefined) - ) - ) { - throw new Error( - `The \`facets\` prop only accepts [] or ["*"], you passed ${JSON.stringify( - props.facets - )}` - ); - } - - if (!results) { - return { attributesToRender: [] }; - } - - const facetOrder = - (results.renderingContent && - results.renderingContent.facetOrdering && - results.renderingContent.facetOrdering.facets && - results.renderingContent.facetOrdering.facets.order) || - []; - - const attributesToRender = props.transformItems(facetOrder, { results }); - - if (attributesToRender.length > MAX_WILDCARD_FACETS && !props.facets) { - // eslint-disable-next-line no-console - console.warn( - `More than ${MAX_WILDCARD_FACETS} facets are requested to be displayed without explicitly setting which facets to retrieve. This could have a performance impact. Set "facets" to [] to do two smaller network requests, or explicitly to ['*'] to avoid this warning.` - ); - } - - if (props.maxValuesPerFacet < results._state.maxValuesPerFacet) { - // eslint-disable-next-line no-console - console.warn( - `The maxValuesPerFacet set by dynamic widgets (${props.maxValuesPerFacet}) is smaller than one of the limits set by a widget (${results._state.maxValuesPerFacet}). This causes a mismatch in query parameters and thus an extra network request when that widget is mounted.` - ); - } - - return { - attributesToRender, - }; - }, - - getSearchParameters(searchParameters, props) { - return (props.facets || ['*']).reduce( - (acc: SearchParameters, curr: string) => acc.addFacet(curr), - searchParameters.setQueryParameters({ - maxValuesPerFacet: Math.max( - props.maxValuesPerFacet || 0, - searchParameters.maxValuesPerFacet || 0 - ), - }) - ); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectGeoSearch.js b/packages/react-instantsearch-core/src/connectors/connectGeoSearch.js deleted file mode 100644 index e11a81d6a4..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectGeoSearch.js +++ /dev/null @@ -1,246 +0,0 @@ -import createConnector from '../core/createConnector'; -import { - getResults, - getCurrentRefinementValue, - getIndexId, - refineValue, - cleanUpValue, -} from '../core/indexUtils'; -import { objectHasKeys } from '../core/utils'; - -/** - * The GeoSearch connector provides the logic to build a widget that will display the results on a map. - * It also provides a way to search for results based on their position. The connector provides function to manage the search experience (search on map interaction). - * @name connectGeoSearch - * @kind connector - * @requirements Note that the GeoSearch connector uses the [geosearch](https://www.algolia.com/doc/guides/searching/geo-search) capabilities of Algolia. - * Your hits **must** have a `_geoloc` attribute in order to be passed to the rendering function. Currently, the feature is not compatible with multiple values in the `_geoloc` attribute - * (e.g. a restaurant with multiple locations). In that case you can duplicate your records and use the [distinct](https://www.algolia.com/doc/guides/ranking/distinct) feature of Algolia to only retrieve unique results. - * @propType {{ northEast: { lat: number, lng: number }, southWest: { lat: number, lng: number } }} [defaultRefinement] - Default search state of the widget containing the bounds for the map - * @providedPropType {function({ northEast: { lat: number, lng: number }, southWest: { lat: number, lng: number } })} refine - a function to toggle the refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {array.} hits - the records that matched the search - * @providedPropType {boolean} isRefinedWithMap - true if the current refinement is set with the map bounds - * @providedPropType {{ northEast: { lat: number, lng: number }, southWest: { lat: number, lng: number } }} [currentRefinement] - the refinement currently applied - * @providedPropType {{ lat: number, lng: number }} [position] - the position of the search - */ - -// To control the map with an external widget the other widget -// **must** write the value in the attribute `aroundLatLng` -const getBoundingBoxId = () => 'boundingBox'; -const getAroundLatLngId = () => 'aroundLatLng'; -const getConfigureAroundLatLngId = () => 'configure.aroundLatLng'; - -const currentRefinementToString = (currentRefinement) => - [ - currentRefinement.northEast.lat, - currentRefinement.northEast.lng, - currentRefinement.southWest.lat, - currentRefinement.southWest.lng, - ].join(); - -const stringToCurrentRefinement = (value) => { - const values = value.split(','); - - return { - northEast: { - lat: parseFloat(values[0]), - lng: parseFloat(values[1]), - }, - southWest: { - lat: parseFloat(values[2]), - lng: parseFloat(values[3]), - }, - }; -}; - -const latLngRegExp = /^(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)$/; -const stringToPosition = (value) => { - const pattern = value.match(latLngRegExp); - - return { - lat: parseFloat(pattern[1]), - lng: parseFloat(pattern[2]), - }; -}; - -const getCurrentRefinement = (props, searchState, context) => { - const refinement = getCurrentRefinementValue( - props, - searchState, - context, - getBoundingBoxId(), - {} - ); - - if (!objectHasKeys(refinement)) { - return; - } - - // eslint-disable-next-line consistent-return - return { - northEast: { - lat: parseFloat(refinement.northEast.lat), - lng: parseFloat(refinement.northEast.lng), - }, - southWest: { - lat: parseFloat(refinement.southWest.lat), - lng: parseFloat(refinement.southWest.lng), - }, - }; -}; - -const getCurrentPosition = (props, searchState, context) => { - const { defaultRefinement, ...propsWithoutDefaultRefinement } = props; - - const aroundLatLng = getCurrentRefinementValue( - propsWithoutDefaultRefinement, - searchState, - context, - getAroundLatLngId() - ); - - if (!aroundLatLng) { - // Fallback on `configure.aroundLatLng` - const configureAroundLatLng = getCurrentRefinementValue( - propsWithoutDefaultRefinement, - searchState, - context, - getConfigureAroundLatLngId() - ); - - return configureAroundLatLng && stringToPosition(configureAroundLatLng); - } - - return aroundLatLng; -}; - -const refine = (searchState, nextValue, context) => { - const resetPage = true; - const nextRefinement = { - [getBoundingBoxId()]: nextValue, - }; - - return refineValue(searchState, nextRefinement, context, resetPage); -}; - -export default createConnector({ - displayName: 'AlgoliaGeoSearch', - $$type: 'ais.geoSearch', - - getProvidedProps(props, searchState, searchResults) { - const context = { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }; - - const results = getResults(searchResults, context); - - // We read it from both because the SearchParameters & the searchState are not always - // in sync. When we set the refinement the searchState is used but when we clear the refinement - // the SearchParameters is used. In the first case when we render, the results are not there - // so we can't find the value from the results. The most up to date value is the searchState. - // But when we clear the refinement the searchState is immediately cleared even when the items - // retrieved are still the one from the previous query with the bounding box. It leads to some - // issue with the position of the map. We should rely on 1 source of truth or at least always - // be sync. - - const currentRefinementFromSearchState = getCurrentRefinement( - props, - searchState, - context - ); - - const currentRefinementFromSearchParameters = - (results && - results._state.insideBoundingBox && - stringToCurrentRefinement(results._state.insideBoundingBox)) || - undefined; - - const currentPositionFromSearchState = getCurrentPosition( - props, - searchState, - context - ); - - const currentPositionFromSearchParameters = - (results && - results._state.aroundLatLng && - stringToPosition(results._state.aroundLatLng)) || - undefined; - - const currentRefinement = - currentRefinementFromSearchState || currentRefinementFromSearchParameters; - - const position = - currentPositionFromSearchState || currentPositionFromSearchParameters; - - return { - hits: !results ? [] : results.hits.filter((_) => Boolean(_._geoloc)), - isRefinedWithMap: Boolean(currentRefinement), - currentRefinement, - position, - }; - }, - - refine(props, searchState, nextValue) { - return refine(searchState, nextValue, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (!currentRefinement) { - return searchParameters; - } - - return searchParameters.setQueryParameter( - 'insideBoundingBox', - currentRefinementToString(currentRefinement) - ); - }, - - cleanUp(props, searchState) { - return cleanUpValue( - searchState, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - getBoundingBoxId() - ); - }, - - getMetadata(props, searchState) { - const items = []; - const id = getBoundingBoxId(); - const context = { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }; - const index = getIndexId(context); - const nextRefinement = {}; - const currentRefinement = getCurrentRefinement(props, searchState, context); - - if (currentRefinement) { - items.push({ - label: `${id}: ${currentRefinementToString(currentRefinement)}`, - value: (nextState) => refine(nextState, nextRefinement, context), - currentRefinement, - }); - } - - return { - id, - index, - items, - }; - }, - - shouldComponentUpdate() { - return true; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectHierarchicalMenu.js b/packages/react-instantsearch-core/src/connectors/connectHierarchicalMenu.js deleted file mode 100644 index 738ddcab6d..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectHierarchicalMenu.js +++ /dev/null @@ -1,312 +0,0 @@ -import algoliasearchHelper from 'algoliasearch-helper'; -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - getIndexId, - refineValue, - getCurrentRefinementValue, - getResults, -} from '../core/indexUtils'; -import { unescapeFacetValue } from '../core/utils'; - -export const getId = (props) => props.attributes[0]; - -const namespace = 'hierarchicalMenu'; - -function getCurrentRefinement(props, searchState, context) { - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - null - ); - - if (currentRefinement === '') { - return null; - } - return currentRefinement; -} - -function getValue(value, props, searchState, context) { - const { id, attributes, separator, rootPath, showParentLevel } = props; - - const currentRefinement = getCurrentRefinement(props, searchState, context); - let nextRefinement; - - if (currentRefinement === null) { - nextRefinement = value; - } else { - const tmpSearchParameters = new algoliasearchHelper.SearchParameters({ - hierarchicalFacets: [ - { - name: id, - attributes, - separator, - rootPath, - showParentLevel, - }, - ], - }); - - nextRefinement = tmpSearchParameters - .toggleHierarchicalFacetRefinement(id, currentRefinement) - .toggleHierarchicalFacetRefinement(id, value) - .getHierarchicalRefinement(id)[0]; - } - - return nextRefinement; -} - -function transformValue(value, props, searchState, context) { - return value.map((v) => ({ - label: v.name, - value: getValue(v.escapedValue, props, searchState, context), - count: v.count, - isRefined: v.isRefined, - items: v.data && transformValue(v.data, props, searchState, context), - })); -} - -const truncate = (items = [], limit = 10) => - items.slice(0, limit).map((item = {}) => - Array.isArray(item.items) - ? { - ...item, - items: truncate(item.items, limit), - } - : item - ); - -function refine(props, searchState, nextRefinement, context) { - const id = getId(props); - const nextValue = { [id]: nextRefinement || '' }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} - -const sortBy = ['name:asc']; - -/** - * connectHierarchicalMenu connector provides the logic to build a widget that will - * give the user the ability to explore a tree-like structure. - * This is commonly used for multi-level categorization of products on e-commerce - * websites. From a UX point of view, we suggest not displaying more than two levels deep. - * @name connectHierarchicalMenu - * @requirements To use this widget, your attributes must be formatted in a specific way. - * If you want for example to have a hierarchical menu of categories, objects in your index - * should be formatted this way: - * - * ```json - * { - * "categories.lvl0": "products", - * "categories.lvl1": "products > fruits", - * "categories.lvl2": "products > fruits > citrus" - * } - * ``` - * - * It's also possible to provide more than one path for each level: - * - * ```json - * { - * "categories.lvl0": ["products", "goods"], - * "categories.lvl1": ["products > fruits", "goods > to eat"] - * } - * ``` - * - * All attributes passed to the `attributes` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * - * @kind connector - * @propType {array.} attributes - List of attributes to use to generate the hierarchy of the menu. See the example for the convention to follow. - * @propType {string} [defaultRefinement] - the item value selected by default - * @propType {boolean} [showMore=false] - Flag to activate the show more button, for toggling the number of items between limit and showMoreLimit. - * @propType {number} [limit=10] - The maximum number of items displayed. - * @propType {number} [showMoreLimit=20] - The maximum number of items displayed when the user triggers the show more. Not considered if `showMore` is false. - * @propType {string} [separator='>'] - Specifies the level separator used in the data. - * @propType {string} [rootPath=null] - The path to use if the first level is not the root level. - * @propType {boolean} [showParentLevel=true] - Flag to set if the parent level should be displayed. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to toggle a refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string} currentRefinement - the refinement currently applied - * @providedPropType {array.<{items: object, count: number, isRefined: boolean, label: string, value: string}>} items - the list of items the HierarchicalMenu can display. items has the same shape as parent items. - */ -export default createConnector({ - displayName: 'AlgoliaHierarchicalMenu', - $$type: 'ais.hierarchicalMenu', - - propTypes: { - attributes: (props, propName, componentName) => { - const isNotString = (val) => typeof val !== 'string'; - if ( - !Array.isArray(props[propName]) || - props[propName].some(isNotString) || - props[propName].length < 1 - ) { - return new Error( - `Invalid prop ${propName} supplied to ${componentName}. Expected an Array of Strings` - ); - } - return undefined; - }, - separator: PropTypes.string, - rootPath: PropTypes.string, - showParentLevel: PropTypes.bool, - defaultRefinement: PropTypes.string, - showMore: PropTypes.bool, - limit: PropTypes.number, - showMoreLimit: PropTypes.number, - transformItems: PropTypes.func, - facetOrdering: PropTypes.bool, - }, - - defaultProps: { - showMore: false, - limit: 10, - showMoreLimit: 20, - separator: ' > ', - rootPath: null, - showParentLevel: true, - facetOrdering: true, - }, - - getProvidedProps(props, searchState, searchResults) { - const { showMore, limit, showMoreLimit, facetOrdering } = props; - const id = getId(props); - - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const isFacetPresent = - Boolean(results) && Boolean(results.getFacetByName(id)); - - if (!isFacetPresent) { - return { - items: [], - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - canRefine: false, - }; - } - const itemsLimit = showMore ? showMoreLimit : limit; - const value = results.getFacetValues(id, { sortBy, facetOrdering }); - const items = value.data - ? transformValue(value.data, props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - : []; - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - return { - items: truncate(transformedItems, itemsLimit), - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - canRefine: transformedItems.length > 0, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const { - attributes, - separator, - rootPath, - showParentLevel, - showMore, - limit, - showMoreLimit, - contextValue, - } = props; - - const id = getId(props); - const itemsLimit = showMore ? showMoreLimit : limit; - - searchParameters = searchParameters - .addHierarchicalFacet({ - name: id, - attributes, - separator, - rootPath, - showParentLevel, - }) - .setQueryParameters({ - maxValuesPerFacet: Math.max( - searchParameters.maxValuesPerFacet || 0, - itemsLimit - ), - }); - - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: contextValue, - multiIndexContext: props.indexContextValue, - }); - if (currentRefinement !== null) { - searchParameters = searchParameters.toggleHierarchicalFacetRefinement( - id, - currentRefinement - ); - } - - return searchParameters; - }, - - getMetadata(props, searchState) { - const rootAttribute = props.attributes[0]; - const id = getId(props); - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const items = !currentRefinement - ? [] - : [ - { - label: `${rootAttribute}: ${unescapeFacetValue(currentRefinement)}`, - attribute: rootAttribute, - value: (nextState) => - refine(props, nextState, '', { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - currentRefinement, - }, - ]; - - return { - id, - index: getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - items, - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectHighlight.js b/packages/react-instantsearch-core/src/connectors/connectHighlight.js deleted file mode 100644 index d44b6391fa..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectHighlight.js +++ /dev/null @@ -1,78 +0,0 @@ -import createConnector from '../core/createConnector'; -import { HIGHLIGHT_TAGS, parseAlgoliaHit } from '../core/highlight'; - -const highlight = ({ - attribute, - hit, - highlightProperty, - preTag = HIGHLIGHT_TAGS.highlightPreTag, - postTag = HIGHLIGHT_TAGS.highlightPostTag, -}) => - parseAlgoliaHit({ - attribute, - highlightProperty, - hit, - preTag, - postTag, - }); - -/** - * connectHighlight connector provides the logic to create an highlighter - * component that will retrieve, parse and render an highlighted attribute - * from an Algolia hit. - * @name connectHighlight - * @kind connector - * @category connector - * @providedPropType {function} highlight - function to retrieve and parse an attribute from a hit. It takes a configuration object with 3 attributes: `highlightProperty` which is the property that contains the highlight structure from the records, `attribute` which is the name of the attribute (it can be either a string or an array of strings) to look for and `hit` which is the hit from Algolia. It returns an array of objects `{value: string, isHighlighted: boolean}`. If the element that corresponds to the attribute is an array of strings, it will return a nested array of objects. - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, SearchBox, Hits, connectHighlight } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const CustomHighlight = connectHighlight( - * ({ highlight, attribute, hit, highlightProperty }) => { - * const highlights = highlight({ - * highlightProperty: '_highlightResult', - * attribute, - * hit - * }); - * - * return highlights.map(part => part.isHighlighted ? ( - * {part.value} - * ) : ( - * {part.value} - * )); - * } - * ); - * - * const Hit = ({ hit }) => ( - *

- * - *

- * ); - * - * const App = () => ( - * - * - * - * - * ); - */ -export default createConnector({ - displayName: 'AlgoliaHighlighter', - $$type: 'ais.highlighter', - - propTypes: {}, - - getProvidedProps() { - return { highlight }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectHitInsights.ts b/packages/react-instantsearch-core/src/connectors/connectHitInsights.ts deleted file mode 100644 index f281523f63..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectHitInsights.ts +++ /dev/null @@ -1,83 +0,0 @@ -import createConnector from '../core/createConnector'; -// @ts-ignore -import { getResults } from '../core/indexUtils'; - -type Results = { index: string }; -type Hit = { objectID: string; __position: number; __queryID: string }; - -type InsightsClient = ( - method: InsightsClientMethod, - payload: InsightsClientPayload -) => void; - -type InsightsClientMethod = - | 'clickedObjectIDsAfterSearch' - | 'convertedObjectIDsAfterSearch'; - -type InsightsClientPayload = { - index: string; - queryID: string; - eventName: string; - objectIDs: string[]; - positions?: number[]; -}; - -function inferPayload({ - method, - results, - currentHit, -}: { - method: InsightsClientMethod; - results: Results; - currentHit: Hit; -}): Omit { - const { index } = results; - const queryID = currentHit.__queryID; - const objectIDs = [currentHit.objectID]; - - if (!queryID) { - throw new Error(`Could not infer \`queryID\`. Ensure \`clickAnalytics: true\` was added with the Configure widget. -See: https://alg.li/VpPpLt`); - } - - switch (method) { - case 'clickedObjectIDsAfterSearch': { - const positions = [currentHit.__position]; - return { index, queryID, objectIDs, positions }; - } - - case 'convertedObjectIDsAfterSearch': - return { index, queryID, objectIDs }; - - default: - throw new Error( - `Unsupported method "${method}" passed to the insights function. The supported methods are: "clickedObjectIDsAfterSearch", "convertedObjectIDsAfterSearch".` - ); - } -} - -const wrapInsightsClient = - (aa: InsightsClient, results: Results, currentHit: Hit) => - (method: InsightsClientMethod, payload: Partial) => { - if (typeof aa !== 'function') { - throw new TypeError(`Expected insightsClient to be a Function`); - } - const inferredPayload = inferPayload({ method, results, currentHit }); - aa(method, { ...inferredPayload, ...payload } as any); - }; - -export default (insightsClient: InsightsClient) => - createConnector({ - displayName: 'AlgoliaInsights', - $$type: 'ais.insights', - - getProvidedProps(props, _, searchResults) { - const results: Results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const insights = wrapInsightsClient(insightsClient, results, props.hit); - return { insights }; - }, - }); diff --git a/packages/react-instantsearch-core/src/connectors/connectHits.js b/packages/react-instantsearch-core/src/connectors/connectHits.js deleted file mode 100644 index 3af94aa261..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectHits.js +++ /dev/null @@ -1,86 +0,0 @@ -import createConnector from '../core/createConnector'; -import { getResults } from '../core/indexUtils'; -import { addAbsolutePositions, addQueryID } from '../core/utils'; - -/** - * connectHits connector provides the logic to create connected - * components that will render the results retrieved from - * Algolia. - * - * To configure the number of hits retrieved, use [HitsPerPage widget](widgets/HitsPerPage.html), - * [connectHitsPerPage connector](connectors/connectHitsPerPage.html) or pass the hitsPerPage - * prop to a [Configure](guide/Search_parameters.html) widget. - * - * **Warning:** you will need to use the **objectID** property available on every hit as a key - * when iterating over them. This will ensure you have the best possible UI experience - * especially on slow networks. - * @name connectHits - * @kind connector - * @providedPropType {array.} hits - the records that matched the search state - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, Highlight, connectHits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * const CustomHits = connectHits(({ hits }) => ( - *
- * {hits.map(hit => - *

- * - *

- * )} - *
- * )); - * - * const App = () => ( - * - * - * - * ); - */ -export default createConnector({ - displayName: 'AlgoliaHits', - $$type: 'ais.hits', - - getProvidedProps(props, searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - if (!results) { - return { hits: [] }; - } - const hitsWithPositions = addAbsolutePositions( - results.hits, - results.hitsPerPage, - results.page - ); - const hitsWithPositionsAndQueryID = addQueryID( - hitsWithPositions, - results.queryID - ); - return { hits: hitsWithPositionsAndQueryID }; - }, - - /* - * Hits needs to be considered as a widget to trigger a search, - * even if no other widgets are used. - * - * To be considered as a widget you need either: - * - getSearchParameters - * - getMetadata - * - transitionState - * - * See: createConnector.tsx - */ - getSearchParameters(searchParameters) { - return searchParameters; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectHitsPerPage.js b/packages/react-instantsearch-core/src/connectors/connectHitsPerPage.js deleted file mode 100644 index 3af521be40..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectHitsPerPage.js +++ /dev/null @@ -1,106 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, -} from '../core/indexUtils'; - -function getId() { - return 'hitsPerPage'; -} - -function getCurrentRefinement(props, searchState, context) { - const id = getId(); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - null - ); - - if (typeof currentRefinement === 'string') { - return parseInt(currentRefinement, 10); - } - return currentRefinement; -} - -/** - * connectHitsPerPage connector provides the logic to create connected - * components that will allow a user to choose to display more or less results from Algolia. - * @name connectHitsPerPage - * @kind connector - * @propType {number} defaultRefinement - The number of items selected by default - * @propType {{value: number, label: string}[]} items - List of hits per page options. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to remove a single filter - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string} currentRefinement - the refinement currently applied - * @providedPropType {array.<{isRefined: boolean, label?: string, value: number}>} items - the list of items the HitsPerPage can display. If no label provided, the value will be displayed. - */ -export default createConnector({ - displayName: 'AlgoliaHitsPerPage', - $$type: 'ais.hitsPerPage', - - propTypes: { - defaultRefinement: PropTypes.number.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string, - value: PropTypes.number.isRequired, - }) - ).isRequired, - transformItems: PropTypes.func, - }, - - getProvidedProps(props, searchState) { - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const items = props.items.map((item) => - item.value === currentRefinement - ? { ...item, isRefined: true } - : { ...item, isRefined: false } - ); - return { - items: props.transformItems ? props.transformItems(items) : items, - currentRefinement, - }; - }, - - refine(props, searchState, nextRefinement) { - const id = getId(); - const nextValue = { [id]: nextRefinement }; - const resetPage = true; - return refineValue( - searchState, - nextValue, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - resetPage - ); - }, - - cleanUp(props, searchState) { - return cleanUpValue( - searchState, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - getId() - ); - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setHitsPerPage( - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ); - }, - - getMetadata() { - return { id: getId() }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectInfiniteHits.js b/packages/react-instantsearch-core/src/connectors/connectInfiniteHits.js deleted file mode 100644 index b28177275d..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectInfiniteHits.js +++ /dev/null @@ -1,150 +0,0 @@ -import isEqual from 'react-fast-compare'; - -import createConnector from '../core/createConnector'; -import { - getCurrentRefinementValue, - refineValue, - getResults, -} from '../core/indexUtils'; -import { addAbsolutePositions, addQueryID } from '../core/utils'; - -function getId() { - return 'page'; -} - -function getCurrentRefinement(props, searchState, context) { - const id = getId(); - const page = 1; - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - page - ); - - if (typeof currentRefinement === 'string') { - return parseInt(currentRefinement, 10); - } - return currentRefinement; -} - -function getStateWithoutPage(state) { - const { page, ...rest } = state || {}; - return rest; -} - -function getInMemoryCache() { - let cachedHits = undefined; - let cachedState = undefined; - return { - read({ state }) { - return isEqual(cachedState, getStateWithoutPage(state)) - ? cachedHits - : null; - }, - write({ state, hits }) { - cachedState = getStateWithoutPage(state); - cachedHits = hits; - }, - }; -} - -function extractHitsFromCachedHits(cachedHits) { - return Object.keys(cachedHits) - .map(Number) - .sort((a, b) => a - b) - .reduce((acc, page) => { - return acc.concat(cachedHits[page]); - }, []); -} - -/** - * InfiniteHits connector provides the logic to create connected - * components that will render an continuous list of results retrieved from - * Algolia. This connector provides a function to load more results. - * @name connectInfiniteHits - * @kind connector - * @providedPropType {array.} hits - the records that matched the search state - * @providedPropType {boolean} hasMore - indicates if there are more pages to load - * @providedPropType {function} refine - call to load more results - */ -export default createConnector({ - displayName: 'AlgoliaInfiniteHits', - $$type: 'ais.infiniteHits', - - getProvidedProps(props, searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (!results) { - return { - hits: [], - hasPrevious: false, - hasMore: false, - refine: () => {}, - refinePrevious: () => {}, - refineNext: () => {}, - }; - } - - const { page, hits, hitsPerPage, nbPages, _state: state } = results; - - this._cache = props.cache ? props.cache : this._cache || getInMemoryCache(); - const cachedHits = this._cache.read({ state }) || {}; - - const hitsWithPositions = addAbsolutePositions(hits, hitsPerPage, page); - const hitsWithPositionsAndQueryID = addQueryID( - hitsWithPositions, - results.queryID - ); - - cachedHits[page] = hitsWithPositionsAndQueryID; - this._cache.write({ state, hits: cachedHits }); - - /* - Math.min() and Math.max() returns Infinity or -Infinity when no argument is given. - But there is always something in this point because of `cachedHits[page]`. - */ - const firstReceivedPage = Math.min(...Object.keys(cachedHits).map(Number)); - const lastReceivedPage = Math.max(...Object.keys(cachedHits).map(Number)); - - const hasPrevious = firstReceivedPage > 0; - const lastPageIndex = nbPages - 1; - const hasMore = lastReceivedPage < lastPageIndex; - const refinePrevious = (event) => this.refine(event, firstReceivedPage - 1); - const refineNext = (event) => this.refine(event, lastReceivedPage + 1); - - return { - hits: extractHitsFromCachedHits(cachedHits), - hasPrevious, - hasMore, - refinePrevious, - refineNext, - }; - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setQueryParameters({ - page: - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - 1, - }); - }, - - refine(props, searchState, event, index) { - const id = getId(); - const nextValue = { [id]: index + 1 }; - const resetPage = false; - return refineValue( - searchState, - nextValue, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - resetPage - ); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectMenu.js b/packages/react-instantsearch-core/src/connectors/connectMenu.js deleted file mode 100644 index 3e470abba7..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectMenu.js +++ /dev/null @@ -1,265 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - getIndexId, - cleanUpValue, - refineValue, - getCurrentRefinementValue, - getResults, -} from '../core/indexUtils'; -import { unescapeFacetValue } from '../core/utils'; - -const namespace = 'menu'; - -function getId(props) { - return props.attribute; -} - -function getCurrentRefinement(props, searchState, context) { - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - null - ); - - if (currentRefinement === '') { - return null; - } - return currentRefinement; -} - -function getValue(value, props, searchState, context) { - const currentRefinement = getCurrentRefinement(props, searchState, context); - return value === currentRefinement ? '' : value; -} - -function getLimit({ showMore, limit, showMoreLimit }) { - return showMore ? showMoreLimit : limit; -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(props); - const nextValue = { [id]: nextRefinement ? nextRefinement : '' }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} - -const defaultSortBy = ['count:desc', 'name:asc']; - -/** - * connectMenu connector provides the logic to build a widget that will - * give the user the ability to choose a single value for a specific facet. - * @name connectMenu - * @requirements The attribute passed to the `attribute` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * @kind connector - * @propType {string} attribute - the name of the attribute in the record - * @propType {boolean} [showMore=false] - true if the component should display a button that will expand the number of items - * @propType {number} [limit=10] - the minimum number of diplayed items - * @propType {number} [showMoreLimit=20] - the maximun number of displayed items. Only used when showMore is set to `true` - * @propType {string} [defaultRefinement] - the value of the item selected by default - * @propType {boolean} [searchable=false] - allow search inside values - * @providedPropType {function} refine - a function to toggle a refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string} currentRefinement - the refinement currently applied - * @providedPropType {array.<{count: number, isRefined: boolean, label: string, value: string}>} items - the list of items the Menu can display. - * @providedPropType {function} searchForItems - a function to toggle a search inside items values - * @providedPropType {boolean} isFromSearch - a boolean that says if the `items` props contains facet values from the global search or from the search inside items. - */ -export default createConnector({ - displayName: 'AlgoliaMenu', - $$type: 'ais.menu', - - propTypes: { - attribute: PropTypes.string.isRequired, - showMore: PropTypes.bool, - limit: PropTypes.number, - showMoreLimit: PropTypes.number, - defaultRefinement: PropTypes.string, - transformItems: PropTypes.func, - searchable: PropTypes.bool, - facetOrdering: PropTypes.bool, - }, - - defaultProps: { - showMore: false, - limit: 10, - showMoreLimit: 20, - facetOrdering: true, - }, - - getProvidedProps( - props, - searchState, - searchResults, - meta, - searchForFacetValuesResults - ) { - const { attribute, searchable, indexContextValue, facetOrdering } = props; - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const canRefine = - Boolean(results) && Boolean(results.getFacetByName(attribute)); - - const isFromSearch = Boolean( - searchForFacetValuesResults && - searchForFacetValuesResults[attribute] && - searchForFacetValuesResults.query !== '' - ); - - // Search For Facet Values is not available with derived helper (used for multi index search) - if (searchable && indexContextValue) { - throw new Error( - 'react-instantsearch: searching in *List is not available when used inside a' + - ' multi index context' - ); - } - - if (!canRefine) { - return { - items: [], - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - isFromSearch, - searchable, - canRefine, - }; - } - - let items; - if (isFromSearch) { - items = searchForFacetValuesResults[attribute].map((v) => ({ - label: v.value, - value: getValue(v.escapedValue, props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - _highlightResult: { label: { value: v.highlighted } }, - count: v.count, - isRefined: v.isRefined, - })); - } else { - items = results - .getFacetValues(attribute, { - sortBy: searchable ? undefined : defaultSortBy, - facetOrdering, - }) - .map((v) => ({ - label: v.name, - value: getValue(v.escapedValue, props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - count: v.count, - isRefined: v.isRefined, - })); - } - - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - - return { - items: transformedItems.slice(0, getLimit(props)), - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - isFromSearch, - searchable, - canRefine: transformedItems.length > 0, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - searchForFacetValues(props, searchState, nextRefinement) { - return { - facetName: props.attribute, - query: nextRefinement, - maxFacetHits: getLimit(props), - }; - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const { attribute } = props; - - searchParameters = searchParameters.setQueryParameters({ - maxValuesPerFacet: Math.max( - searchParameters.maxValuesPerFacet || 0, - getLimit(props) - ), - }); - - searchParameters = searchParameters.addDisjunctiveFacet(attribute); - - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - if (currentRefinement !== null) { - searchParameters = searchParameters.addDisjunctiveFacetRefinement( - attribute, - currentRefinement - ); - } - - return searchParameters; - }, - - getMetadata(props, searchState) { - const id = getId(props); - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - return { - id, - index: getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - items: - currentRefinement === null - ? [] - : [ - { - label: `${props.attribute}: ${unescapeFacetValue( - currentRefinement - )}`, - attribute: props.attribute, - value: (nextState) => - refine(props, nextState, '', { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - currentRefinement, - }, - ], - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectNumericMenu.js b/packages/react-instantsearch-core/src/connectors/connectNumericMenu.js deleted file mode 100644 index 4cc353a599..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectNumericMenu.js +++ /dev/null @@ -1,252 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, - getResults, - getIndexId, -} from '../core/indexUtils'; -import { find } from '../core/utils'; - -function stringifyItem(item) { - if (typeof item.start === 'undefined' && typeof item.end === 'undefined') { - return ''; - } - const start = typeof item.start !== 'undefined' ? item.start : ''; - const end = typeof item.end !== 'undefined' ? item.end : ''; - return `${start}:${end}`; -} - -function parseItem(value) { - if (value.length === 0) { - return { start: null, end: null }; - } - const [startStr, endStr] = value.split(':'); - return { - start: startStr.length > 0 ? parseFloat(startStr) : null, - end: endStr.length > 0 ? parseFloat(endStr) : null, - }; -} - -const namespace = 'multiRange'; - -function getId(props) { - return props.attribute; -} - -function getCurrentRefinement(props, searchState, context) { - return getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - '', - (currentRefinement) => { - if (currentRefinement === '') { - return ''; - } - return currentRefinement; - } - ); -} - -function isRefinementsRangeIncludesInsideItemRange(stats, start, end) { - return ( - (stats.min >= start && stats.min <= end) || - (stats.max >= start && stats.max <= end) - ); -} - -function isItemRangeIncludedInsideRefinementsRange(stats, start, end) { - return ( - (start >= stats.min && start <= stats.max) || - (end >= stats.min && end <= stats.max) - ); -} - -function itemHasRefinement(attribute, results, value) { - const stats = results.getFacetByName(attribute) - ? results.getFacetStats(attribute) - : null; - const range = value.split(':'); - const start = - Number(range[0]) === 0 || value === '' - ? Number.NEGATIVE_INFINITY - : Number(range[0]); - const end = - Number(range[1]) === 0 || value === '' - ? Number.POSITIVE_INFINITY - : Number(range[1]); - return !( - Boolean(stats) && - (isRefinementsRangeIncludesInsideItemRange(stats, start, end) || - isItemRangeIncludedInsideRefinementsRange(stats, start, end)) - ); -} - -function refine(props, searchState, nextRefinement, context) { - const nextValue = { [getId(props, searchState)]: nextRefinement }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} - -/** - * connectNumericMenu connector provides the logic to build a widget that will - * give the user the ability to select a range value for a numeric attribute. - * Ranges are defined statically. - * @name connectNumericMenu - * @requirements The attribute passed to the `attribute` prop must be holding numerical values. - * @kind connector - * @propType {string} attribute - the name of the attribute in the records - * @propType {{label: string, start: number, end: number}[]} items - List of options. With a text label, and upper and lower bounds. - * @propType {string} [defaultRefinement] - the value of the item selected by default, follow the shape of a `string` with a pattern of `'{start}:{end}'`. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to select a range. - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string} currentRefinement - the refinement currently applied. follow the shape of a `string` with a pattern of `'{start}:{end}'` which corresponds to the current selected item. For instance, when the selected item is `{start: 10, end: 20}`, the searchState of the widget is `'10:20'`. When `start` isn't defined, the searchState of the widget is `':{end}'`, and the same way around when `end` isn't defined. However, when neither `start` nor `end` are defined, the searchState is an empty string. - * @providedPropType {array.<{isRefined: boolean, label: string, value: string, isRefined: boolean, noRefinement: boolean}>} items - the list of ranges the NumericMenu can display. - */ -export default createConnector({ - displayName: 'AlgoliaNumericMenu', - $$type: 'ais.numericMenu', - - propTypes: { - id: PropTypes.string, - attribute: PropTypes.string.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.node, - start: PropTypes.number, - end: PropTypes.number, - }) - ).isRequired, - transformItems: PropTypes.func, - }, - - getProvidedProps(props, searchState, searchResults) { - const attribute = props.attribute; - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const items = props.items.map((item) => { - const value = stringifyItem(item); - return { - label: item.label, - value, - isRefined: value === currentRefinement, - noRefinement: results - ? itemHasRefinement(getId(props), results, value) - : false, - }; - }); - - const stats = - results && results.getFacetByName(attribute) - ? results.getFacetStats(attribute) - : null; - const refinedItem = find(items, (item) => item.isRefined === true); - if (!items.some((item) => item.value === '')) { - items.push({ - value: '', - isRefined: refinedItem === undefined, - noRefinement: !stats, - label: 'All', - }); - } - - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - - return { - items: transformedItems, - currentRefinement, - canRefine: - transformedItems.length > 0 && - transformedItems.some((item) => item.noRefinement === false), - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const { attribute } = props; - const { start, end } = parseItem( - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ); - searchParameters = searchParameters.addDisjunctiveFacet(attribute); - - if (typeof start === 'number') { - searchParameters = searchParameters.addNumericRefinement( - attribute, - '>=', - start - ); - } - if (typeof end === 'number') { - searchParameters = searchParameters.addNumericRefinement( - attribute, - '<=', - end - ); - } - return searchParameters; - }, - - getMetadata(props, searchState) { - const id = getId(props); - const value = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const items = []; - const index = getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - if (value !== '') { - const { label } = find( - props.items, - (item) => stringifyItem(item) === value - ); - items.push({ - label: `${props.attribute}: ${label}`, - attribute: props.attribute, - currentRefinement: label, - value: (nextState) => - refine(props, nextState, '', { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - }); - } - return { id, index, items }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectPagination.js b/packages/react-instantsearch-core/src/connectors/connectPagination.js deleted file mode 100644 index 0879adb0a5..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectPagination.js +++ /dev/null @@ -1,105 +0,0 @@ -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, - getResults, -} from '../core/indexUtils'; - -function getId() { - return 'page'; -} - -function getCurrentRefinement(props, searchState, context) { - const id = getId(); - const page = 1; - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - page - ); - - if (typeof currentRefinement === 'string') { - return parseInt(currentRefinement, 10); - } - return currentRefinement; -} - -function refine(props, searchState, nextPage, context) { - const id = getId(); - const nextValue = { [id]: nextPage }; - const resetPage = false; - return refineValue(searchState, nextValue, context, resetPage); -} - -/** - * connectPagination connector provides the logic to build a widget that will - * let the user displays hits corresponding to a certain page. - * @name connectPagination - * @kind connector - * @propType {boolean} [showFirst=true] - Display the first page link. - * @propType {boolean} [showLast=false] - Display the last page link. - * @propType {boolean} [showPrevious=true] - Display the previous page link. - * @propType {boolean} [showNext=true] - Display the next page link. - * @propType {number} [padding=3] - How many page links to display around the current page. - * @propType {number} [totalPages=Infinity] - Maximum number of pages to display. - * @providedPropType {function} refine - a function to remove a single filter - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {number} nbPages - the total of existing pages - * @providedPropType {number} currentRefinement - the page refinement currently applied - */ -export default createConnector({ - displayName: 'AlgoliaPagination', - $$type: 'ais.pagination', - - getProvidedProps(props, searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (!results) { - return null; - } - - const nbPages = results.nbPages; - return { - nbPages, - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - canRefine: nbPages > 1, - }; - }, - - refine(props, searchState, nextPage) { - return refine(props, searchState, nextPage, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUpValue( - searchState, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - getId() - ); - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setPage( - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - 1 - ); - }, - - getMetadata() { - return { id: getId() }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectPoweredBy.js b/packages/react-instantsearch-core/src/connectors/connectPoweredBy.js deleted file mode 100644 index bb5d4e39e4..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectPoweredBy.js +++ /dev/null @@ -1,31 +0,0 @@ -import createConnector from '../core/createConnector'; - -/** - * connectPoweredBy connector provides the logic to build a widget that - * will display a link to algolia. - * @name connectPoweredBy - * @kind connector - * @providedPropType {string} url - the url to redirect to algolia - */ -export default createConnector({ - displayName: 'AlgoliaPoweredBy', - $$type: 'ais.poweredBy', - - getProvidedProps() { - const hostname = - typeof window === 'undefined' || typeof window.location === 'undefined' - ? '' - : window.location.hostname; - - const url = - 'https://www.algolia.com/?' + - 'utm_source=react-instantsearch&' + - 'utm_medium=website&' + - `utm_content=${hostname}&` + - 'utm_campaign=poweredby'; - - return { - url, - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectQueryRules.ts b/packages/react-instantsearch-core/src/connectors/connectQueryRules.ts deleted file mode 100644 index 4e8ec955cc..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectQueryRules.ts +++ /dev/null @@ -1,201 +0,0 @@ -import createConnector from '../core/createConnector'; -// @ts-ignore -import { getResults, getIndexId, hasMultipleIndices } from '../core/indexUtils'; - -import type { ConnectedProps } from '../core/createConnector'; - -type SearchState = any; - -type SearchParameters = any; - -export type CustomUserData = { - [key: string]: any; -}; - -type TrackedFilterRefinement = string | number | boolean; - -export type QueryRulesProps = { - trackedFilters: { - [facetName: string]: ( - facetValues: TrackedFilterRefinement[] - ) => TrackedFilterRefinement[]; - }; - transformRuleContexts: (ruleContexts: string[]) => string[]; - transformItems: (items: TItem[]) => TItem[]; -}; - -// A context rule must consist only of alphanumeric characters, hyphens, and underscores. -// See https://www.algolia.com/doc/guides/managing-results/refine-results/merchandising-and-promoting/in-depth/implementing-query-rules/#context -function escapeRuleContext(ruleName: string): string { - return ruleName.replace(/[^a-z0-9-_]+/gi, '_'); -} - -function getWidgetRefinements( - attribute: string, - widgetKey: string, - searchState: SearchState -): TrackedFilterRefinement[] { - const widgetState = searchState[widgetKey]; - - switch (widgetKey) { - case 'range': - return Object.keys(widgetState[attribute]).map( - (rangeKey) => widgetState[attribute][rangeKey] - ); - - case 'refinementList': - return widgetState[attribute]; - - case 'hierarchicalMenu': - return [widgetState[attribute]]; - - case 'menu': - return [widgetState[attribute]]; - - case 'multiRange': - return widgetState[attribute].split(':'); - - case 'toggle': - return [widgetState[attribute]]; - - default: - return []; - } -} - -function getRefinements( - attribute: string, - searchState: SearchState = {} -): TrackedFilterRefinement[] { - const refinements = Object.keys(searchState) - .filter( - (widgetKey) => - searchState[widgetKey] !== undefined && - searchState[widgetKey][attribute] !== undefined - ) - .map((widgetKey) => getWidgetRefinements(attribute, widgetKey, searchState)) - .reduce((acc, current) => acc.concat(current), []); // flatten the refinements - - return refinements; -} - -function getRuleContextsFromTrackedFilters({ - searchState, - trackedFilters, -}: { - searchState: SearchState; - trackedFilters: QueryRulesProps['trackedFilters']; -}) { - const ruleContexts = Object.keys(trackedFilters).reduce( - (facets, facetName) => { - const facetRefinements: TrackedFilterRefinement[] = getRefinements( - facetName, - searchState - ); - - const getTrackedFacetValues = trackedFilters[facetName]; - const trackedFacetValues = getTrackedFacetValues(facetRefinements); - - return [ - ...facets, - ...facetRefinements - .filter((facetRefinement) => - trackedFacetValues.includes(facetRefinement) - ) - .map((facetValue) => - escapeRuleContext(`ais-${facetName}-${facetValue}`) - ), - ]; - }, - [] - ); - - return ruleContexts; -} - -const defaultProps: QueryRulesProps = { - transformItems: (items) => items, - transformRuleContexts: (ruleContexts) => ruleContexts, - trackedFilters: {}, -}; - -export default createConnector({ - displayName: 'AlgoliaQueryRules', - $$type: 'ais.queryRules', - - defaultProps, - - getProvidedProps( - props: ConnectedProps, - _1: any, - searchResults: any - ) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (results === null) { - return { - items: [], - canRefine: false, - }; - } - - const { userData = [] } = results; - const { transformItems } = props; - const transformedItems = transformItems(userData); - - return { - items: transformedItems, - canRefine: transformedItems.length > 0, - }; - }, - - getSearchParameters( - searchParameters: SearchParameters, - props: ConnectedProps, - searchState: SearchState - ) { - if (Object.keys(props.trackedFilters).length === 0) { - return searchParameters; - } - - const indexSearchState = - hasMultipleIndices({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) && searchState.indices - ? searchState.indices[ - getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ] - : searchState; - - const newRuleContexts = getRuleContextsFromTrackedFilters({ - searchState: indexSearchState, - trackedFilters: props.trackedFilters, - }); - - const initialRuleContexts = searchParameters.ruleContexts || []; - const nextRuleContexts = [...initialRuleContexts, ...newRuleContexts]; - - if (process.env.NODE_ENV === 'development') { - if (nextRuleContexts.length > 10) { - // eslint-disable-next-line no-console - console.warn( - `The maximum number of \`ruleContexts\` is 10. They have been sliced to that limit. -Consider using \`transformRuleContexts\` to minimize the number of rules sent to Algolia.` - ); - } - } - - const ruleContexts = props - .transformRuleContexts(nextRuleContexts) - .slice(0, 10); - - return searchParameters.setQueryParameter('ruleContexts', ruleContexts); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectRange.js b/packages/react-instantsearch-core/src/connectors/connectRange.js deleted file mode 100644 index c82223d54e..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectRange.js +++ /dev/null @@ -1,343 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - getIndexId, - refineValue, - getCurrentRefinementValue, - getResults, -} from '../core/indexUtils'; - -/** - * connectRange connector provides the logic to create connected - * components that will give the ability for a user to refine results using - * a numeric range. - * @name connectRange - * @kind connector - * @requirements The attribute passed to the `attribute` prop must be present in “attributes for faceting” - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * The values inside the attribute must be JavaScript numbers (not strings). - * @propType {string} attribute - Name of the attribute for faceting - * @propType {{min?: number, max?: number}} [defaultRefinement] - Default searchState of the widget containing the start and the end of the range. - * @propType {number} [min] - Minimum value. When this isn't set, the minimum value will be automatically computed by Algolia using the data in the index. - * @propType {number} [max] - Maximum value. When this isn't set, the maximum value will be automatically computed by Algolia using the data in the index. - * @propType {number} [precision=0] - Number of digits after decimal point to use. - * @providedPropType {function} refine - a function to select a range. - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string} currentRefinement - the refinement currently applied - * @providedPropType {number} min - the minimum value available. - * @providedPropType {number} max - the maximum value available. - * @providedPropType {number} precision - Number of digits after decimal point to use. - */ - -function getId(props) { - return props.attribute; -} - -const namespace = 'range'; - -function getCurrentRange(boundaries, stats, precision) { - const pow = Math.pow(10, precision); - - let min; - if (typeof boundaries.min === 'number' && isFinite(boundaries.min)) { - min = boundaries.min; - } else if (typeof stats.min === 'number' && isFinite(stats.min)) { - min = stats.min; - } else { - min = undefined; - } - - let max; - if (typeof boundaries.max === 'number' && isFinite(boundaries.max)) { - max = boundaries.max; - } else if (typeof stats.max === 'number' && isFinite(stats.max)) { - max = stats.max; - } else { - max = undefined; - } - - return { - min: min !== undefined ? Math.floor(min * pow) / pow : min, - max: max !== undefined ? Math.ceil(max * pow) / pow : max, - }; -} - -function getCurrentRefinement(props, searchState, currentRange, context) { - const { min, max } = getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - {} - ); - - const isFloatPrecision = Boolean(props.precision); - - let nextMin = min; - if (typeof nextMin === 'string') { - nextMin = isFloatPrecision ? parseFloat(nextMin) : parseInt(nextMin, 10); - } - - let nextMax = max; - if (typeof nextMax === 'string') { - nextMax = isFloatPrecision ? parseFloat(nextMax) : parseInt(nextMax, 10); - } - - const refinement = { - min: nextMin, - max: nextMax, - }; - - const hasMinBound = props.min !== undefined; - const hasMaxBound = props.max !== undefined; - - const hasMinRefinment = refinement.min !== undefined; - const hasMaxRefinment = refinement.max !== undefined; - - if (hasMinBound && hasMinRefinment && refinement.min < currentRange.min) { - throw Error("You can't provide min value lower than range."); - } - - if (hasMaxBound && hasMaxRefinment && refinement.max > currentRange.max) { - throw Error("You can't provide max value greater than range."); - } - - if (hasMinBound && !hasMinRefinment) { - refinement.min = currentRange.min; - } - - if (hasMaxBound && !hasMaxRefinment) { - refinement.max = currentRange.max; - } - - return refinement; -} - -function getCurrentRefinementWithRange(refinement, range) { - return { - min: refinement.min !== undefined ? refinement.min : range.min, - max: refinement.max !== undefined ? refinement.max : range.max, - }; -} - -function nextValueForRefinement(hasBound, isReset, range, value) { - let next; - if (!hasBound && range === value) { - next = undefined; - } else if (hasBound && isReset) { - next = range; - } else { - next = value; - } - - return next; -} - -function refine(props, searchState, nextRefinement, currentRange, context) { - const { min: nextMin, max: nextMax } = nextRefinement; - const { min: currentMinRange, max: currentMaxRange } = currentRange; - - const isMinReset = nextMin === undefined || nextMin === ''; - const isMaxReset = nextMax === undefined || nextMax === ''; - - const nextMinAsNumber = !isMinReset ? parseFloat(nextMin) : undefined; - const nextMaxAsNumber = !isMaxReset ? parseFloat(nextMax) : undefined; - - const isNextMinValid = isMinReset || isFinite(nextMinAsNumber); - const isNextMaxValid = isMaxReset || isFinite(nextMaxAsNumber); - - if (!isNextMinValid || !isNextMaxValid) { - throw Error("You can't provide non finite values to the range connector."); - } - - if (nextMinAsNumber < currentMinRange) { - throw Error("You can't provide min value lower than range."); - } - - if (nextMaxAsNumber > currentMaxRange) { - throw Error("You can't provide max value greater than range."); - } - - const id = getId(props); - const resetPage = true; - const nextValue = { - [id]: { - min: nextValueForRefinement( - props.min !== undefined, - isMinReset, - currentMinRange, - nextMinAsNumber - ), - max: nextValueForRefinement( - props.max !== undefined, - isMaxReset, - currentMaxRange, - nextMaxAsNumber - ), - }, - }; - - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} - -export default createConnector({ - displayName: 'AlgoliaRange', - $$type: 'ais.range', - - propTypes: { - id: PropTypes.string, - attribute: PropTypes.string.isRequired, - defaultRefinement: PropTypes.shape({ - min: PropTypes.number, - max: PropTypes.number, - }), - min: PropTypes.number, - max: PropTypes.number, - precision: PropTypes.number, - header: PropTypes.node, - footer: PropTypes.node, - }, - - defaultProps: { - precision: 0, - }, - - getProvidedProps(props, searchState, searchResults) { - const { attribute, precision, min: minBound, max: maxBound } = props; - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const hasFacet = results && results.getFacetByName(attribute); - const stats = hasFacet ? results.getFacetStats(attribute) || {} : {}; - const facetValues = hasFacet ? results.getFacetValues(attribute) : []; - - const count = facetValues.map((v) => ({ - value: v.name, - count: v.count, - })); - - const { min: rangeMin, max: rangeMax } = getCurrentRange( - { min: minBound, max: maxBound }, - stats, - precision - ); - - // The searchState is not always in sync with the helper state. For example - // when we set boundaries on the first render the searchState don't have - // the correct refinement. If this behavior change in the upcoming version - // we could store the range inside the searchState instead of rely on `this`. - this._currentRange = { - min: rangeMin, - max: rangeMax, - }; - - const currentRefinement = getCurrentRefinement( - props, - searchState, - this._currentRange, - { ais: props.contextValue, multiIndexContext: props.indexContextValue } - ); - - return { - min: rangeMin, - max: rangeMax, - canRefine: count.length > 0, - currentRefinement: getCurrentRefinementWithRange( - currentRefinement, - this._currentRange - ), - count, - precision, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, this._currentRange, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(params, props, searchState) { - const { attribute } = props; - const { min, max } = getCurrentRefinement( - props, - searchState, - this._currentRange, - { ais: props.contextValue, multiIndexContext: props.indexContextValue } - ); - - params = params.addDisjunctiveFacet(attribute); - - if (min !== undefined) { - params = params.addNumericRefinement(attribute, '>=', min); - } - - if (max !== undefined) { - params = params.addNumericRefinement(attribute, '<=', max); - } - - return params; - }, - - getMetadata(props, searchState) { - const { min: minRange, max: maxRange } = this._currentRange; - const { min: minValue, max: maxValue } = getCurrentRefinement( - props, - searchState, - this._currentRange, - { ais: props.contextValue, multiIndexContext: props.indexContextValue } - ); - - const items = []; - const hasMin = minValue !== undefined; - const hasMax = maxValue !== undefined; - const shouldDisplayMinLabel = hasMin && minValue !== minRange; - const shouldDisplayMaxLabel = hasMax && maxValue !== maxRange; - - if (shouldDisplayMinLabel || shouldDisplayMaxLabel) { - const fragments = [ - hasMin ? `${minValue} <= ` : '', - props.attribute, - hasMax ? ` <= ${maxValue}` : '', - ]; - - items.push({ - label: fragments.join(''), - attribute: props.attribute, - value: (nextState) => - refine(props, nextState, {}, this._currentRange, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - currentRefinement: getCurrentRefinementWithRange( - { min: minValue, max: maxValue }, - { min: minRange, max: maxRange } - ), - }); - } - - return { - id: getId(props), - index: getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - items, - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectRefinementList.js b/packages/react-instantsearch-core/src/connectors/connectRefinementList.js deleted file mode 100644 index eb4efc27e5..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectRefinementList.js +++ /dev/null @@ -1,293 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - getIndexId, - refineValue, - getCurrentRefinementValue, - getResults, -} from '../core/indexUtils'; -import { unescapeFacetValue } from '../core/utils'; - -const namespace = 'refinementList'; - -function getId(props) { - return props.attribute; -} - -function getCurrentRefinement(props, searchState, context) { - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - [] - ); - - if (typeof currentRefinement !== 'string') { - return currentRefinement; - } - - if (currentRefinement) { - return [currentRefinement]; - } - - return []; -} - -function getValue(value, props, searchState, context) { - const currentRefinement = getCurrentRefinement(props, searchState, context); - const isAnewValue = currentRefinement.indexOf(value) === -1; - const nextRefinement = isAnewValue - ? currentRefinement.concat([value]) // cannot use .push(), it mutates - : currentRefinement.filter((selectedValue) => selectedValue !== value); // cannot use .splice(), it mutates - return nextRefinement; -} - -function getLimit({ showMore, limit, showMoreLimit }) { - return showMore ? showMoreLimit : limit; -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(props); - // Setting the value to an empty string ensures that it is persisted in - // the URL as an empty value. - // This is necessary in the case where `defaultRefinement` contains one - // item and we try to deselect it. `nextSelected` would be an empty array, - // which would not be persisted to the URL. - // {foo: ['bar']} => "foo[0]=bar" - // {foo: []} => "" - const nextValue = { [id]: nextRefinement.length > 0 ? nextRefinement : '' }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} -/** - * connectRefinementList connector provides the logic to build a widget that will - * give the user the ability to choose multiple values for a specific facet. - * @name connectRefinementList - * @kind connector - * @requirements The attribute passed to the `attribute` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * @propType {string} attribute - the name of the attribute in the record - * @propType {boolean} [searchable=false] - allow search inside values - * @propType {string} [operator=or] - How to apply the refinements. Possible values: 'or' or 'and'. - * @propType {boolean} [showMore=false] - true if the component should display a button that will expand the number of items - * @propType {number} [limit=10] - the minimum number of displayed items - * @propType {number} [showMoreLimit=20] - the maximun number of displayed items. Only used when showMore is set to `true` - * @propType {string[]} defaultRefinement - the values of the items selected by default. The searchState of this widget takes the form of a list of `string`s, which correspond to the values of all selected refinements. However, when there are no refinements selected, the value of the searchState is an empty string. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to toggle a refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string[]} currentRefinement - the refinement currently applied - * @providedPropType {array.<{count: number, isRefined: boolean, label: string, value: string}>} items - the list of items the RefinementList can display. - * @providedPropType {function} searchForItems - a function to toggle a search inside items values - * @providedPropType {boolean} isFromSearch - a boolean that says if the `items` props contains facet values from the global search or from the search inside items. - * @providedPropType {boolean} canRefine - a boolean that says whether you can refine - */ - -const sortBy = ['isRefined', 'count:desc', 'name:asc']; -export default createConnector({ - displayName: 'AlgoliaRefinementList', - $$type: 'ais.refinementList', - - propTypes: { - id: PropTypes.string, - attribute: PropTypes.string.isRequired, - operator: PropTypes.oneOf(['and', 'or']), - showMore: PropTypes.bool, - limit: PropTypes.number, - showMoreLimit: PropTypes.number, - defaultRefinement: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - ), - searchable: PropTypes.bool, - transformItems: PropTypes.func, - facetOrdering: PropTypes.bool, - }, - - defaultProps: { - operator: 'or', - showMore: false, - limit: 10, - showMoreLimit: 20, - facetOrdering: true, - }, - - getProvidedProps( - props, - searchState, - searchResults, - metadata, - searchForFacetValuesResults - ) { - const { attribute, searchable, indexContextValue, facetOrdering } = props; - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const canRefine = - Boolean(results) && Boolean(results.getFacetByName(attribute)); - - const isFromSearch = Boolean( - searchForFacetValuesResults && - searchForFacetValuesResults[attribute] && - searchForFacetValuesResults.query !== '' - ); - - // Search For Facet Values is not available with derived helper (used for multi index search) - if (searchable && indexContextValue) { - throw new Error( - 'react-instantsearch: searching in *List is not available when used inside a' + - ' multi index context' - ); - } - - if (!canRefine) { - return { - items: [], - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - canRefine, - isFromSearch, - searchable, - }; - } - - const items = isFromSearch - ? searchForFacetValuesResults[attribute].map((v) => ({ - label: v.value, - value: getValue(v.escapedValue, props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - _highlightResult: { label: { value: v.highlighted } }, - count: v.count, - isRefined: v.isRefined, - })) - : results - .getFacetValues(attribute, { sortBy, facetOrdering }) - .map((v) => ({ - label: v.name, - value: getValue(v.escapedValue, props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - count: v.count, - isRefined: v.isRefined, - })); - - const transformedItems = props.transformItems - ? props.transformItems(items) - : items; - - return { - items: transformedItems.slice(0, getLimit(props)), - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - isFromSearch, - searchable, - canRefine: transformedItems.length > 0, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - searchForFacetValues(props, searchState, nextRefinement) { - return { - facetName: props.attribute, - query: nextRefinement, - maxFacetHits: getLimit(props), - }; - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const { attribute, operator } = props; - - const addKey = operator === 'and' ? 'addFacet' : 'addDisjunctiveFacet'; - const addRefinementKey = `${addKey}Refinement`; - - searchParameters = searchParameters.setQueryParameters({ - maxValuesPerFacet: Math.max( - searchParameters.maxValuesPerFacet || 0, - getLimit(props) - ), - }); - - searchParameters = searchParameters[addKey](attribute); - - return getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }).reduce( - (res, val) => res[addRefinementKey](attribute, val), - searchParameters - ); - }, - - getMetadata(props, searchState) { - const id = getId(props); - const context = { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }; - return { - id, - index: getIndexId(context), - items: - getCurrentRefinement(props, searchState, context).length > 0 - ? [ - { - attribute: props.attribute, - label: `${props.attribute}: `, - currentRefinement: getCurrentRefinement( - props, - searchState, - context - ), - value: (nextState) => refine(props, nextState, [], context), - items: getCurrentRefinement(props, searchState, context).map( - (item) => ({ - label: unescapeFacetValue(`${item}`), - value: (nextState) => { - const nextSelectedItems = getCurrentRefinement( - props, - nextState, - context - ).filter((other) => other !== item); - return refine( - props, - searchState, - nextSelectedItems, - context - ); - }, - }) - ), - }, - ] - : [], - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectRelevantSort.ts b/packages/react-instantsearch-core/src/connectors/connectRelevantSort.ts deleted file mode 100644 index 1b2aa2b308..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectRelevantSort.ts +++ /dev/null @@ -1,79 +0,0 @@ -import createConnector from '../core/createConnector'; -import { - refineValue, - getCurrentRefinementValue, - getResults, - // @ts-ignore -} from '../core/indexUtils'; - -import type { ConnectedProps } from '../core/createConnector'; - -function getId() { - return 'relevancyStrictness'; -} - -function getCurrentRefinement( - props: ConnectedProps, - searchState: any, - context: any -) { - const id = getId(); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id - ); - - return currentRefinement; -} - -export default createConnector({ - displayName: 'AlgoliaRelevantSort', - $$type: 'ais.relevantSort', - - getProvidedProps(props, _searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (!results) { - return { - isVirtualReplica: false, - isRelevantSorted: false, - }; - } - - return { - isVirtualReplica: results.appliedRelevancyStrictness !== undefined, - isRelevantSorted: - results.appliedRelevancyStrictness !== undefined && - results.appliedRelevancyStrictness > 0, - }; - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setQueryParameter( - 'relevancyStrictness', - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ); - }, - - refine(props, searchState, nextRefinement) { - const nextValue = { - [getId()]: nextRefinement, - }; - const resetPage = true; - - return refineValue( - searchState, - nextValue, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - resetPage - ); - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectScrollTo.js b/packages/react-instantsearch-core/src/connectors/connectScrollTo.js deleted file mode 100644 index e6cc357c7f..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectScrollTo.js +++ /dev/null @@ -1,84 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - getCurrentRefinementValue, - hasMultipleIndices, - getIndexId, -} from '../core/indexUtils'; -import { shallowEqual, omit } from '../core/utils'; - -/** - * connectScrollTo connector provides the logic to build a widget that will - * let the page scroll to a certain point. - * @name connectScrollTo - * @kind connector - * @propType {string} [scrollOn="page"] - Widget searchState key on which to listen for changes, default to the pagination widget. - * @providedPropType {any} value - the current refinement applied to the widget listened by scrollTo - * @providedPropType {boolean} hasNotChanged - indicates whether the refinement came from the scrollOn argument (for instance page by default) - */ -export default createConnector({ - displayName: 'AlgoliaScrollTo', - $$type: 'ais.scrollTo', - - propTypes: { - scrollOn: PropTypes.string, - }, - - defaultProps: { - scrollOn: 'page', - }, - - getProvidedProps(props, searchState) { - const id = props.scrollOn; - const value = getCurrentRefinementValue( - props, - searchState, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - id, - null - ); - - if (!this._prevSearchState) { - this._prevSearchState = {}; - } - - // Get the subpart of the state that interest us - if ( - hasMultipleIndices({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ) { - searchState = searchState.indices - ? searchState.indices[ - getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ] - : {}; - } - - // if there is a change in the app that has been triggered by another element - // than "props.scrollOn (id) or the Configure widget, we need to keep track of - // the search state to know if there's a change in the app that was not triggered - // by the props.scrollOn (id) or the Configure widget. This is useful when - // using ScrollTo in combination of Pagination. As pagination can be change - // by every widget, we want to scroll only if it cames from the pagination - // widget itself. We also remove the configure key from the search state to - // do this comparison because for now configure values are not present in the - // search state before a first refinement has been made and will false the results. - // See: https://github.com/algolia/react-instantsearch/issues/164 - const cleanedSearchState = omit(searchState, ['configure', id]); - - const hasNotChanged = shallowEqual( - this._prevSearchState, - cleanedSearchState - ); - - this._prevSearchState = cleanedSearchState; - - return { value, hasNotChanged }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectSearchBox.js b/packages/react-instantsearch-core/src/connectors/connectSearchBox.js deleted file mode 100644 index 2f7c9cbec7..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectSearchBox.js +++ /dev/null @@ -1,121 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, - getIndexId, -} from '../core/indexUtils'; - -function getId() { - return 'query'; -} - -function getCurrentRefinement(props, searchState, context) { - const id = getId(props); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - '' - ); - - if (currentRefinement) { - return currentRefinement; - } - return ''; -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(); - const nextValue = { [id]: nextRefinement }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, getId()); -} - -/** - * connectSearchBox connector provides the logic to build a widget that will - * let the user search for a query - * @name connectSearchBox - * @kind connector - * @propType {string} [defaultRefinement] - Provide a default value for the query - * @providedPropType {function} refine - a function to change the current query - * @providedPropType {string} currentRefinement - the current query used - * @providedPropType {boolean} isSearchStalled - a flag that indicates if InstantSearch has detected that searches are stalled - */ -export default createConnector({ - displayName: 'AlgoliaSearchBox', - $$type: 'ais.searchBox', - - propTypes: { - defaultRefinement: PropTypes.string, - }, - - getProvidedProps(props, searchState, searchResults) { - return { - currentRefinement: getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - isSearchStalled: searchResults.isSearchStalled, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - return searchParameters.setQuery( - getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }) - ); - }, - - getMetadata(props, searchState) { - const id = getId(props); - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - return { - id, - index: getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - items: - currentRefinement === null - ? [] - : [ - { - label: `${id}: ${currentRefinement}`, - value: (nextState) => - refine(props, nextState, '', { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - currentRefinement, - }, - ], - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectSortBy.js b/packages/react-instantsearch-core/src/connectors/connectSortBy.js deleted file mode 100644 index 19f24603c6..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectSortBy.js +++ /dev/null @@ -1,107 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, -} from '../core/indexUtils'; - -function getId() { - return 'sortBy'; -} - -function getCurrentRefinement(props, searchState, context) { - const id = getId(props); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - null - ); - - if (currentRefinement) { - return currentRefinement; - } - return null; -} - -/** - * The connectSortBy connector provides the logic to build a widget that will - * display a list of indices. This allows a user to change how the hits are being sorted. - * @name connectSortBy - * @requirements Algolia handles sorting by creating replica indices. [Read more about sorting](https://www.algolia.com/doc/guides/relevance/sorting/) on - * the Algolia website. - * @kind connector - * @propType {string} defaultRefinement - The default selected index. - * @propType {{value: string, label: string}[]} items - The list of indexes to search in. - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @providedPropType {function} refine - a function to remove a single filter - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - * @providedPropType {string[]} currentRefinement - the refinement currently applied - * @providedPropType {array.<{isRefined: boolean, label?: string, value: string}>} items - the list of items the HitsPerPage can display. If no label provided, the value will be displayed. - */ -export default createConnector({ - displayName: 'AlgoliaSortBy', - $$type: 'ais.sortBy', - - propTypes: { - defaultRefinement: PropTypes.string, - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string, - value: PropTypes.string.isRequired, - }) - ).isRequired, - transformItems: PropTypes.func, - }, - - getProvidedProps(props, searchState) { - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const items = props.items.map((item) => - item.value === currentRefinement - ? { ...item, isRefined: true } - : { ...item, isRefined: false } - ); - return { - items: props.transformItems ? props.transformItems(items) : items, - currentRefinement, - }; - }, - - refine(props, searchState, nextRefinement) { - const id = getId(); - const nextValue = { [id]: nextRefinement }; - const resetPage = true; - return refineValue( - searchState, - nextValue, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - resetPage - ); - }, - - cleanUp(props, searchState) { - return cleanUpValue( - searchState, - { ais: props.contextValue, multiIndexContext: props.indexContextValue }, - getId() - ); - }, - - getSearchParameters(searchParameters, props, searchState) { - const selectedIndex = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - return searchParameters.setIndex(selectedIndex); - }, - - getMetadata() { - return { id: getId() }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectStateResults.js b/packages/react-instantsearch-core/src/connectors/connectStateResults.js deleted file mode 100644 index 63e7f80a14..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectStateResults.js +++ /dev/null @@ -1,74 +0,0 @@ -import createConnector from '../core/createConnector'; -import { getResults } from '../core/indexUtils'; - -/** - * The `connectStateResults` connector provides a way to access the `searchState` and the `searchResults` - * of InstantSearch. - * For instance this connector allows you to create results/noResults or query/noQuery pages. - * @name connectStateResults - * @kind connector - * @providedPropType {object} searchState - The search state of the instant search component.

See: [Search state structure](https://community.algolia.com/react-instantsearch/guide/Search_state.html) - * @providedPropType {object} searchResults - The search results.

In case of multiple indices: if used under ``, results will be those of the corresponding index otherwise it'll be those of the root index See: [Search results structure](https://community.algolia.com/algoliasearch-helper-js/reference.html#searchresults) - * @providedPropType {object} allSearchResults - In case of multiple indices you can retrieve all the results - * @providedPropType {string} error - If the search failed, the error will be logged here. - * @providedPropType {boolean} searching - If there is a search in progress. - * @providedPropType {boolean} isSearchStalled - Flag that indicates if React InstantSearch has detected that searches are stalled. - * @providedPropType {boolean} searchingForFacetValues - If there is a search in a list in progress. - * @providedPropType {object} props - component props. - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, SearchBox, Hits, connectStateResults } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const Content = connectStateResults(({ searchState, searchResults }) => { - * const hasResults = searchResults && searchResults.nbHits !== 0; - * - * return ( - *
- * - * - *
- * ); - * }); - * - * const App = () => ( - * - * - * - * - * ); - */ -export default createConnector({ - displayName: 'AlgoliaStateResults', - $$type: 'ais.stateResults', - - getProvidedProps(props, searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - return { - searchState, - searchResults: results, - allSearchResults: searchResults.results, - searching: searchResults.searching, - isSearchStalled: searchResults.isSearchStalled, - error: searchResults.error, - searchingForFacetValues: searchResults.searchingForFacetValues, - props, - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectStats.ts b/packages/react-instantsearch-core/src/connectors/connectStats.ts deleted file mode 100644 index bc66ec36ce..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectStats.ts +++ /dev/null @@ -1,38 +0,0 @@ -import createConnector from '../core/createConnector'; -// @ts-ignore -import { getResults } from '../core/indexUtils'; - -/** - * connectStats connector provides the logic to build a widget that will - * displays algolia search statistics (hits number and processing time). - * @name connectStats - * @kind connector - * @providedPropType {number} nbHits - number of hits returned by Algolia. - * @providedPropType {number} nbSortedHits - number of sorted hits returned by Algolia. - * @providedPropType {number} processingTimeMS - the time in ms took by Algolia to search for results. - */ -export default createConnector({ - displayName: 'AlgoliaStats', - $$type: 'ais.stats', - - getProvidedProps(props, _searchState, searchResults) { - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (!results) { - return null; - } - - return { - areHitsSorted: - results.appliedRelevancyStrictness !== undefined && - results.appliedRelevancyStrictness > 0 && - results.nbHits !== results.nbSortedHits, - nbHits: results.nbHits, - nbSortedHits: results.nbSortedHits, - processingTimeMS: results.processingTimeMS, - }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectToggleRefinement.js b/packages/react-instantsearch-core/src/connectors/connectToggleRefinement.js deleted file mode 100644 index 1b63fbcf98..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectToggleRefinement.js +++ /dev/null @@ -1,190 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - getIndexId, - getResults, - refineValue, - getCurrentRefinementValue, -} from '../core/indexUtils'; -import { find } from '../core/utils'; - -function getId(props) { - return props.attribute; -} - -const namespace = 'toggle'; - -const falsyStrings = ['0', 'false', 'null', 'undefined']; - -function getCurrentRefinement(props, searchState, context) { - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - `${namespace}.${getId(props)}`, - false - ); - - if (falsyStrings.indexOf(currentRefinement) !== -1) { - return false; - } - - return Boolean(currentRefinement); -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(props); - const nextValue = { [id]: nextRefinement ? nextRefinement : false }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage, namespace); -} - -function cleanUp(props, searchState, context) { - return cleanUpValue(searchState, context, `${namespace}.${getId(props)}`); -} - -/** - * connectToggleRefinement connector provides the logic to build a widget that will - * provides an on/off filtering feature based on an attribute value. - * @name connectToggleRefinement - * @kind connector - * @requirements To use this widget, you'll need an attribute to toggle on. - * - * You can't toggle on null or not-null values. If you want to address this particular use-case you'll need to compute an - * extra boolean attribute saying if the value exists or not. See this [thread](https://discourse.algolia.com/t/how-to-create-a-toggle-for-the-absence-of-a-string-attribute/2460) for more details. - * - * @propType {string} attribute - Name of the attribute on which to apply the `value` refinement. Required when `value` is present. - * @propType {string} label - Label for the toggle. - * @propType {string} value - Value of the refinement to apply on `attribute`. - * @propType {boolean} [defaultRefinement=false] - Default searchState of the widget. Should the toggle be checked by default? - * @providedPropType {boolean} currentRefinement - `true` when the refinement is applied, `false` otherwise - * @providedPropType {object} count - an object that contains the count for `checked` and `unchecked` state - * @providedPropType {function} refine - a function to toggle a refinement - * @providedPropType {function} createURL - a function to generate a URL for the corresponding search state - */ -export default createConnector({ - displayName: 'AlgoliaToggle', - $$type: 'ais.toggle', - - propTypes: { - label: PropTypes.string.isRequired, - attribute: PropTypes.string.isRequired, - value: PropTypes.any.isRequired, - filter: PropTypes.func, - defaultRefinement: PropTypes.bool, - }, - - getProvidedProps(props, searchState, searchResults) { - const { attribute, value } = props; - const results = getResults(searchResults, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const currentRefinement = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - const allFacetValues = - results && results.getFacetByName(attribute) - ? results.getFacetValues(attribute) - : null; - - const facetValue = - // Use null to always be consistent with type of the value - // count: number | null - allFacetValues && allFacetValues.length - ? find(allFacetValues, (item) => item.name === value.toString()) - : null; - - const facetValueCount = facetValue && facetValue.count; - const allFacetValuesCount = - // Use null to always be consistent with type of the value - // count: number | null - allFacetValues && allFacetValues.length - ? allFacetValues.reduce((acc, item) => acc + item.count, 0) - : null; - - const canRefine = currentRefinement - ? allFacetValuesCount !== null && allFacetValuesCount > 0 - : facetValueCount !== null && facetValueCount > 0; - - const count = { - checked: allFacetValuesCount, - unchecked: facetValueCount, - }; - - return { - currentRefinement, - canRefine, - count, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const { attribute, value, filter } = props; - const checked = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - let nextSearchParameters = searchParameters.addDisjunctiveFacet(attribute); - - if (checked) { - nextSearchParameters = nextSearchParameters.addDisjunctiveFacetRefinement( - attribute, - value - ); - - if (filter) { - nextSearchParameters = filter(nextSearchParameters); - } - } - - return nextSearchParameters; - }, - - getMetadata(props, searchState) { - const id = getId(props); - const checked = getCurrentRefinement(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const items = []; - const index = getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - - if (checked) { - items.push({ - label: props.label, - currentRefinement: checked, - attribute: props.attribute, - value: (nextState) => - refine(props, nextState, false, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - }); - } - - return { id, index, items }; - }, -}); diff --git a/packages/react-instantsearch-core/src/connectors/connectVoiceSearch.js b/packages/react-instantsearch-core/src/connectors/connectVoiceSearch.js deleted file mode 100644 index ee6ce4abf9..0000000000 --- a/packages/react-instantsearch-core/src/connectors/connectVoiceSearch.js +++ /dev/null @@ -1,161 +0,0 @@ -import PropTypes from 'prop-types'; - -import createConnector from '../core/createConnector'; -import { - cleanUpValue, - refineValue, - getCurrentRefinementValue, - getIndexId, -} from '../core/indexUtils'; - -function getId() { - return 'query'; -} - -function getAdditionalId() { - return 'additionalVoiceParameters'; -} - -function getCurrentRefinementQuery(props, searchState, context) { - const id = getId(); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - '' - ); - - if (currentRefinement) { - return currentRefinement; - } - return ''; -} - -function getCurrentRefinementAdditional(props, searchState, context) { - const id = getAdditionalId(); - const currentRefinement = getCurrentRefinementValue( - props, - searchState, - context, - id, - '' - ); - - if (currentRefinement) { - return currentRefinement; - } - return {}; -} - -function refine(props, searchState, nextRefinement, context) { - const id = getId(); - const voiceParams = getAdditionalId(); - const queryLanguages = props.language - ? { queryLanguages: [props.language.split('-')[0]] } - : {}; - const additionalQueryParameters = - typeof props.additionalQueryParameters === 'function' - ? { - ignorePlurals: true, - removeStopWords: true, - optionalWords: nextRefinement, - ...props.additionalQueryParameters({ query: nextRefinement }), - } - : {}; - const nextValue = { - [id]: nextRefinement, - [voiceParams]: { - ...queryLanguages, - ...additionalQueryParameters, - }, - }; - const resetPage = true; - return refineValue(searchState, nextValue, context, resetPage); -} - -function cleanUp(props, searchState, context) { - const interimState = cleanUpValue(searchState, context, getId()); - return cleanUpValue(interimState, context, getAdditionalId()); -} - -export default createConnector({ - displayName: 'AlgoliaVoiceSearch', - $$type: 'ais.voiceSearch', - - propTypes: { - defaultRefinement: PropTypes.string, - }, - - getProvidedProps(props, searchState, searchResults) { - return { - currentRefinement: getCurrentRefinementQuery(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - isSearchStalled: searchResults.isSearchStalled, - }; - }, - - refine(props, searchState, nextRefinement) { - return refine(props, searchState, nextRefinement, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - cleanUp(props, searchState) { - return cleanUp(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - }, - - getSearchParameters(searchParameters, props, searchState) { - const query = getCurrentRefinementQuery(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - const additionalParams = getCurrentRefinementAdditional( - props, - searchState, - { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - } - ); - - return searchParameters - .setQuery(query) - .setQueryParameters(additionalParams); - }, - - getMetadata(props, searchState) { - const id = getId(); - const currentRefinement = getCurrentRefinementQuery(props, searchState, { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }); - return { - id, - index: getIndexId({ - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - items: - currentRefinement === null - ? [] - : [ - { - label: `${id}: ${currentRefinement}`, - value: (nextState) => - refine(props, nextState, '', { - ais: props.contextValue, - multiIndexContext: props.indexContextValue, - }), - currentRefinement, - }, - ], - }; - }, -}); diff --git a/packages/react-instantsearch-hooks/src/connectors/useBreadcrumb.ts b/packages/react-instantsearch-core/src/connectors/useBreadcrumb.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useBreadcrumb.ts rename to packages/react-instantsearch-core/src/connectors/useBreadcrumb.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useClearRefinements.ts b/packages/react-instantsearch-core/src/connectors/useClearRefinements.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useClearRefinements.ts rename to packages/react-instantsearch-core/src/connectors/useClearRefinements.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useConfigure.ts b/packages/react-instantsearch-core/src/connectors/useConfigure.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useConfigure.ts rename to packages/react-instantsearch-core/src/connectors/useConfigure.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useCurrentRefinements.ts b/packages/react-instantsearch-core/src/connectors/useCurrentRefinements.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useCurrentRefinements.ts rename to packages/react-instantsearch-core/src/connectors/useCurrentRefinements.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useDynamicWidgets.ts b/packages/react-instantsearch-core/src/connectors/useDynamicWidgets.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useDynamicWidgets.ts rename to packages/react-instantsearch-core/src/connectors/useDynamicWidgets.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useGeoSearch.ts b/packages/react-instantsearch-core/src/connectors/useGeoSearch.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useGeoSearch.ts rename to packages/react-instantsearch-core/src/connectors/useGeoSearch.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useHierarchicalMenu.ts b/packages/react-instantsearch-core/src/connectors/useHierarchicalMenu.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useHierarchicalMenu.ts rename to packages/react-instantsearch-core/src/connectors/useHierarchicalMenu.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useHits.ts b/packages/react-instantsearch-core/src/connectors/useHits.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useHits.ts rename to packages/react-instantsearch-core/src/connectors/useHits.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useHitsPerPage.ts b/packages/react-instantsearch-core/src/connectors/useHitsPerPage.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useHitsPerPage.ts rename to packages/react-instantsearch-core/src/connectors/useHitsPerPage.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useInfiniteHits.ts b/packages/react-instantsearch-core/src/connectors/useInfiniteHits.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useInfiniteHits.ts rename to packages/react-instantsearch-core/src/connectors/useInfiniteHits.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useMenu.ts b/packages/react-instantsearch-core/src/connectors/useMenu.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useMenu.ts rename to packages/react-instantsearch-core/src/connectors/useMenu.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useNumericMenu.ts b/packages/react-instantsearch-core/src/connectors/useNumericMenu.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useNumericMenu.ts rename to packages/react-instantsearch-core/src/connectors/useNumericMenu.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/usePagination.ts b/packages/react-instantsearch-core/src/connectors/usePagination.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/usePagination.ts rename to packages/react-instantsearch-core/src/connectors/usePagination.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/usePoweredBy.ts b/packages/react-instantsearch-core/src/connectors/usePoweredBy.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/usePoweredBy.ts rename to packages/react-instantsearch-core/src/connectors/usePoweredBy.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useQueryRules.ts b/packages/react-instantsearch-core/src/connectors/useQueryRules.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useQueryRules.ts rename to packages/react-instantsearch-core/src/connectors/useQueryRules.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useRange.ts b/packages/react-instantsearch-core/src/connectors/useRange.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useRange.ts rename to packages/react-instantsearch-core/src/connectors/useRange.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useRefinementList.ts b/packages/react-instantsearch-core/src/connectors/useRefinementList.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useRefinementList.ts rename to packages/react-instantsearch-core/src/connectors/useRefinementList.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useSearchBox.ts b/packages/react-instantsearch-core/src/connectors/useSearchBox.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useSearchBox.ts rename to packages/react-instantsearch-core/src/connectors/useSearchBox.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useSortBy.ts b/packages/react-instantsearch-core/src/connectors/useSortBy.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useSortBy.ts rename to packages/react-instantsearch-core/src/connectors/useSortBy.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useStats.ts b/packages/react-instantsearch-core/src/connectors/useStats.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useStats.ts rename to packages/react-instantsearch-core/src/connectors/useStats.ts diff --git a/packages/react-instantsearch-hooks/src/connectors/useToggleRefinement.ts b/packages/react-instantsearch-core/src/connectors/useToggleRefinement.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/connectors/useToggleRefinement.ts rename to packages/react-instantsearch-core/src/connectors/useToggleRefinement.ts diff --git a/packages/react-instantsearch-core/src/core/__tests__/createConnector.js b/packages/react-instantsearch-core/src/core/__tests__/createConnector.js deleted file mode 100644 index f8fa419152..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createConnector.js +++ /dev/null @@ -1,1422 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { wait } from '@instantsearch/testutils'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount, shallow } from 'enzyme'; -import React from 'react'; - -import { InstantSearchProvider } from '../context'; -import createConnector, { - createConnectorWithoutContext, -} from '../createConnector'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('createConnector', () => { - const createFakeState = (props) => ({ - widgets: {}, - results: {}, - resultsFacetValues: {}, - searching: false, - searchingForFacetValues: false, - isSearchStalled: false, - metadata: [], - error: new Error(), - ...props, - }); - - const createFakeStore = (props) => ({ - getState: () => createFakeState(), - setState() {}, - subscribe() {}, - ...props, - }); - - const createFakeWidgetManager = (props) => ({ - registerWidget() {}, - getWidgets() {}, - update() {}, - ...props, - }); - - const createFakeContext = (props) => ({ - onInternalStateUpdate() {}, - createHrefForState() {}, - onSearchForFacetValues() {}, - onSearchStateChange() {}, - onSearchParameters() {}, - store: createFakeStore(), - widgetsManager: createFakeWidgetManager(), - ...props, - }); - - describe('state', () => { - it('computes provided props', () => { - const getProvidedProps = jest.fn((props) => ({ - providedProps: props, - })); - - const Fake = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const state = createFakeState(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - }); - - const wrapper = shallow(); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - expect(getProvidedProps).toHaveBeenCalledWith( - { hello: 'there', contextValue: context }, - state.widgets, - { - results: state.results, - searching: state.searching, - searchingForFacetValues: state.searchingForFacetValues, - isSearchStalled: state.isSearchStalled, - error: state.error, - }, - state.metadata, - state.resultsFacetValues - ); - - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'there', - providedProps: { - hello: 'there', - contextValue: context, - }, - }); - }); - - it('computes provided props on props change', () => { - const getProvidedProps = jest.fn((props) => ({ - providedProps: props, - })); - - const Fake = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const props = { - hello: 'there', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - - wrapper.setProps({ - hello: 'again', - }); - - expect(getProvidedProps).toHaveBeenCalledTimes(2); - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'again', - providedProps: { - hello: 'again', - contextValue: context, - }, - }); - }); - - it('computes provided props with the correct value for `canRender` on props change', () => { - const getProvidedProps = jest.fn((props) => ({ - providedProps: props, - })); - - const Fake = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const props = { - hello: 'there', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - // Simulate props change before mount - wrapper.setProps({ hello: 'again' }); - - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'again', - providedProps: { - hello: 'again', - contextValue: context, - }, - }); - - // Simulate mount lifecycle - wrapper.instance().componentDidMount(); - - // Simulate props change after mount - wrapper.setProps({ hello: 'once again' }); - - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'once again', - providedProps: { - hello: 'once again', - contextValue: context, - }, - }); - }); - - it('computes provided props on search state change', () => { - const getProvidedProps = jest.fn((_, state) => state); - - const Fake = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const subscribe = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: jest.fn(() => state), - subscribe, - }), - }); - - const wrapper = shallow(); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'there', - query: 'hello', - }); - - // Simulate a search state change - context.store.getState.mockImplementation(() => ({ - ...state, - widgets: { - query: 'hello World', - }, - })); - - // Simulate a dispatch on search state change - context.store.subscribe.mock.calls[0][0](); - - expect(getProvidedProps).toHaveBeenCalledTimes(2); - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'there', - query: 'hello World', - }); - }); - - it('computes provided props with latest props on search state change', () => { - const getProvidedProps = jest.fn((_, state) => state); - - const Fake = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const subscribe = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: jest.fn(() => state), - subscribe, - }), - }); - - const wrapper = shallow(); - - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'there', - query: 'hello', - }); - - // Simulate a search state change - context.store.getState.mockImplementation(() => ({ - ...state, - widgets: { - query: 'hello world', - }, - })); - - // Simulate a props change - wrapper.setProps({ - hello: 'again', - }); - - // Simulate a dispatch on search state change - context.store.subscribe.mock.calls[0][0](); - - expect(wrapper.find(Fake).props()).toEqual({ - hello: 'again', - query: 'hello world', - }); - }); - - it('does not compute provided props when props do not change', () => { - const getProvidedProps = jest.fn((props) => ({ - providedProps: props, - })); - - const Fake = jest.fn(() => null); - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps, - })(Fake); - - const props = { - hello: 'again', - another: ['one', 'two'], - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - - wrapper.setProps({ - hello: 'again', - another: ['one', 'two'], - }); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - - wrapper.setProps({ - hello: 'again', - another: ['one', 'two'], - }); - - expect(getProvidedProps).toHaveBeenCalledTimes(1); - }); - - it('use shouldComponentUpdate when provided', () => { - const shouldComponentUpdate = jest.fn(() => true); - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: (props) => props, - getMetadata: () => null, - shouldComponentUpdate, - })(() => null); - - const props = { hello: 'there' }; - const context = createFakeContext(); - const wrapper = mount(); - - expect(shouldComponentUpdate).toHaveBeenCalledTimes(0); - - wrapper.setProps({ hello: 'here' }); - - expect(shouldComponentUpdate).toHaveBeenCalledTimes(2); - expect(shouldComponentUpdate).toHaveBeenCalledWith( - { - hello: 'there', - contextValue: context, - }, - { - hello: 'here', - contextValue: context, - }, - { - providedProps: { - hello: 'there', - contextValue: context, - }, - }, - { - providedProps: { - hello: 'there', - contextValue: context, - }, - } - ); - - expect(shouldComponentUpdate).toHaveBeenCalledWith( - { - hello: 'here', - contextValue: context, - }, - { - hello: 'here', - contextValue: context, - }, - { - providedProps: { - hello: 'there', - contextValue: context, - }, - }, - { - providedProps: { - hello: 'here', - contextValue: context, - }, - } - ); - }); - - it('subscribes to the store once mounted', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const subscribe = jest.fn(); - - const context = createFakeContext({ - store: createFakeStore({ - subscribe, - }), - }); - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(subscribe).toHaveBeenCalledTimes(0); - - // Simulate didMount - wrapper.instance().componentDidMount(); - - expect(subscribe).toHaveBeenCalledTimes(1); - }); - - it('unsubscribes from the store on unmount', async () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const unsubscribe = jest.fn(); - - const context = createFakeContext({ - store: createFakeStore({ - subscribe: () => unsubscribe, - }), - }); - - const wrapper = shallow(); - - expect(unsubscribe).toHaveBeenCalledTimes(0); - - wrapper.unmount(); - - await wait(0); - - expect(unsubscribe).toHaveBeenCalledTimes(1); - }); - - it('does not throw an error on unmount before mount', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const context = createFakeContext({ - store: createFakeStore({ - subscribe() { - return () => { - // unsubscribe - }; - }, - }), - }); - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(() => wrapper.unmount()).not.toThrow(); - }); - - it('does not throw an error on dispatch after unmount', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const unsubscribe = () => {}; - const subscribe = jest.fn(() => unsubscribe); - - const context = createFakeContext({ - store: createFakeStore({ - subscribe, - }), - }); - - const wrapper = shallow(); - - expect(() => () => { - wrapper.unmount(); - - // Simulate a dispatch - subscribe.mock.calls[0][0](); - }).not.toThrow(); - }); - }); - - describe('widget', () => { - it('registers itself as a widget with getMetadata', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const registerWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget, - }), - }); - - const wrapper = shallow(); - - expect(registerWidget).toHaveBeenCalledTimes(1); - expect(registerWidget).toHaveBeenCalledWith(wrapper.instance()); - }); - - it('registers itself as a widget with getSearchParameters', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getSearchParameters: () => null, - })(() => null); - - const registerWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget, - }), - }); - - const wrapper = shallow(); - - expect(registerWidget).toHaveBeenCalledTimes(1); - expect(registerWidget).toHaveBeenCalledWith(wrapper.instance()); - }); - - it('registers itself as a widget once mounted', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getSearchParameters: () => null, - })(() => null); - - const registerWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget, - }), - }); - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(registerWidget).toHaveBeenCalledTimes(0); - - // Simulate didMount - wrapper.instance().componentDidMount(); - - expect(registerWidget).toHaveBeenCalledTimes(1); - expect(registerWidget).toHaveBeenCalledWith(wrapper.instance()); - }); - - it('does not register itself as a widget without getMetadata nor getSearchParameters', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const registerWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget, - }), - }); - - shallow(); - - expect(registerWidget).not.toHaveBeenCalled(); - }); - - it('calls onSearchParameters on mount with getSearchParameters', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'CoolConnector', - getProvidedProps: () => {}, - getSearchParameters: () => null, - getMetadata: () => null, - })(() => null); - - const onSearchParameters = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - onSearchParameters, - }); - - shallow(); - - expect(onSearchParameters).toHaveBeenCalledTimes(1); - expect(onSearchParameters).toHaveBeenCalledWith( - expect.any(Function), - { ais: context }, - { ...props, contextValue: context }, - expect.any(Function), - 'CoolConnector' - ); - }); - - it('does not call onSearchParameters on mount without getSearchParameters', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'CoolConnector', - getProvidedProps: () => {}, - })(() => null); - - const onSearchParameters = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - onSearchParameters, - }); - - shallow(); - - expect(onSearchParameters).not.toHaveBeenCalled(); - }); - - it('binds getSearchParameters to the connector instance with onSearchParameters', () => { - const getSearchParameters = jest.fn(function () { - return this; - }); - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getSearchParameters, - })(() => null); - - const onSearchParameters = jest.fn(); - - const context = createFakeContext({ - onSearchParameters, - }); - - const wrapper = shallow(); - - expect(onSearchParameters.mock.calls[0][0]()).toBe(wrapper.instance()); - }); - - it('triggers a widgetManager update on props change', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const update = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - update, - }), - }); - - const wrapper = shallow(); - - expect(update).toHaveBeenCalledTimes(0); - - wrapper.setProps({ - hello: 'again', - }); - - expect(update).toHaveBeenCalledTimes(1); - }); - - it('does not trigger a widgetManager update when props do not change', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const update = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - update, - }), - }); - - const wrapper = shallow(); - - expect(update).toHaveBeenCalledTimes(0); - - wrapper.setProps({ - hello: 'there', - }); - - expect(update).toHaveBeenCalledTimes(0); - }); - - it('triggers an onSearchStateChange on props change with transitionState', () => { - const transitionState = jest.fn(function () { - return this.props; - }); - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - transitionState, - })(() => null); - - const state = createFakeState(); - const onSearchStateChange = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - onSearchStateChange, - }); - - const wrapper = shallow(); - - expect(onSearchStateChange).toHaveBeenCalledTimes(0); - expect(transitionState).toHaveBeenCalledTimes(0); - - wrapper.setProps({ - hello: 'again', - }); - - expect(onSearchStateChange).toHaveBeenCalledTimes(1); - expect(onSearchStateChange).toHaveBeenCalledWith({ - hello: 'again', - contextValue: context, - }); - - expect(transitionState).toHaveBeenCalledTimes(1); - expect(transitionState).toHaveBeenCalledWith( - { hello: 'again', contextValue: context }, - state.widgets, - state.widgets - ); - }); - - it('does not trigger an onSearchStateChange on props change without transitionState', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const onSearchStateChange = jest.fn(); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - onSearchStateChange, - }); - - const wrapper = shallow(); - - expect(onSearchStateChange).not.toHaveBeenCalled(); - - wrapper.setProps({ - hello: 'again', - }); - - expect(onSearchStateChange).not.toHaveBeenCalled(); - }); - - it('unregisters itself on unmount', async () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const unregisterWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget: () => unregisterWidget, - }), - }); - - const wrapper = shallow(); - - expect(unregisterWidget).toHaveBeenCalledTimes(0); - - wrapper.unmount(); - - await wait(0); - - expect(unregisterWidget).toHaveBeenCalledTimes(1); - }); - - it('calls onSearchStateChange with cleanUp on unmount', async () => { - const cleanUp = jest.fn(function (props, searchState) { - return { - instanceProps: this.props, - providedProps: props, - searchState, - }; - }); - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - cleanUp, - })(() => null); - - const onSearchStateChange = jest.fn(); - const setState = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - setState, - }), - widgetsManager: createFakeWidgetManager({ - registerWidget: () => () => {}, - }), - onSearchStateChange, - }); - - const wrapper = shallow(); - - expect(cleanUp).toHaveBeenCalledTimes(0); - expect(onSearchStateChange).toHaveBeenCalledTimes(0); - - wrapper.unmount(); - - await wait(0); - - expect(cleanUp).toHaveBeenCalledTimes(1); - expect(onSearchStateChange).toHaveBeenCalledTimes(1); - expect(onSearchStateChange).toHaveBeenCalledWith({ - providedProps: { - hello: 'there', - contextValue: context, - }, - instanceProps: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - }); - }); - - it('calls onSearchStateChange with cleanUp without empty keys on unmount', async () => { - const cleanUp = jest.fn((_, searchState) => searchState); - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - cleanUp, - })(() => null); - - const onSearchStateChange = jest.fn(); - const setState = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - hello: {}, - }, - }); - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - setState, - }), - widgetsManager: createFakeWidgetManager({ - registerWidget: () => () => {}, - }), - onSearchStateChange, - }); - - const wrapper = shallow(); - - wrapper.unmount(); - - await wait(0); - - expect(onSearchStateChange).toHaveBeenCalledWith({ - query: 'hello', - }); - }); - - it('does not throw an error on unmount before mount', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata: () => null, - })(() => null); - - const unregisterWidget = jest.fn(); - - const context = createFakeContext({ - widgetsManager: createFakeWidgetManager({ - registerWidget: () => unregisterWidget, - }), - }); - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - const trigger = () => wrapper.unmount(); - - expect(() => trigger()).not.toThrow(); - }); - }); - - describe('getSearchParameters', () => { - it('returns the widget search parameters when getSearchParameters is provided', () => { - const getSearchParameters = function ( - searchParameters, - props, - searchState - ) { - return { - instanceProps: this.props, - providedProps: props, - searchParameters, - searchState, - }; - }; - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getSearchParameters, - })(() => null); - - const searchParameters = { - query: '', - hitsPerPage: 10, - }; - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - }); - - const wrapper = shallow(); - - const widgetSearchParameters = wrapper - .instance() - .getSearchParameters(searchParameters); - - expect(widgetSearchParameters).toEqual({ - searchParameters: { - query: '', - hitsPerPage: 10, - }, - instanceProps: { - hello: 'there', - contextValue: context, - }, - providedProps: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - }); - }); - - it('returns null when getSearchParameters is not provided', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const searchParameters = { - query: '', - hitsPerPage: 10, - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - const widgetSearchParamameters = wrapper - .instance() - .getSearchParameters(searchParameters); - - expect(widgetSearchParamameters).toBe(null); - }); - }); - - describe('getMetadata', () => { - it('returns the widget metadata when getMetadata is provided', () => { - const getMetadata = function (props, searchState) { - return { - instanceProps: this.props, - providedProps: props, - searchState, - }; - }; - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - getMetadata, - })(() => null); - - const props = { - hello: 'there', - }; - - const searchState = { - query: 'hello', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - const widgetMetadata = wrapper.instance().getMetadata(searchState); - - expect(widgetMetadata).toEqual({ - instanceProps: { - hello: 'there', - contextValue: context, - }, - providedProps: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - }); - }); - - it('returns an empty object when getMetadata is not provided', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const searchState = { - query: 'hello', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - const widgetMetadata = wrapper.instance().getMetadata(searchState); - - expect(widgetMetadata).toEqual({}); - }); - }); - - describe('transitionState', () => { - it('returns the widget transitionState when transitionState is provided', () => { - const transitionState = function ( - props, - previousSearchState, - nextSearchState - ) { - return { - instanceProps: this.props, - providedProps: props, - previousSearchState, - nextSearchState, - }; - }; - - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - transitionState, - })(() => null); - - const props = { - hello: 'there', - }; - - const previousSearchState = { - query: 'hello', - }; - - const nextSearchState = { - query: 'hello again', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - const widgetTransitionState = wrapper - .instance() - .transitionState(previousSearchState, nextSearchState); - - expect(widgetTransitionState).toEqual({ - instanceProps: { - hello: 'there', - contextValue: context, - }, - providedProps: { - hello: 'there', - contextValue: context, - }, - previousSearchState: { - query: 'hello', - }, - nextSearchState: { - query: 'hello again', - }, - }); - }); - - it('returns the given next state when transitionState is not provided', () => { - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - })(() => null); - - const props = { - hello: 'there', - }; - - const previousSearchState = { - query: 'hello', - }; - - const nextSearchState = { - query: 'hello again', - }; - - const context = createFakeContext(); - - const wrapper = shallow(); - - const widgetTransitionState = wrapper - .instance() - .transitionState(previousSearchState, nextSearchState); - - expect(widgetTransitionState).toEqual({ - query: 'hello again', - }); - }); - }); - - describe('refine', () => { - it('passes a refine method to the component', () => { - const refine = (props, searchState, next) => ({ - props, - searchState, - next, - }); - - const Dummy = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - refine, - })(Dummy); - - const onInternalStateUpdate = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - onInternalStateUpdate, - }); - - const wrapper = shallow(); - - expect(onInternalStateUpdate).toHaveBeenCalledTimes(0); - - wrapper.find(Dummy).props().refine({ query: 'hello world' }); - - expect(onInternalStateUpdate).toHaveBeenCalledTimes(1); - expect(onInternalStateUpdate).toHaveBeenCalledWith({ - props: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - next: { - query: 'hello world', - }, - }); - }); - }); - - describe('createURL', () => { - it('passes a createURL method to the component', () => { - const refine = (props, searchState, next) => ({ - props, - searchState, - next, - }); - - const Dummy = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - refine, - })(Dummy); - - const createHrefForState = jest.fn(); - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const props = { - hello: 'there', - }; - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - createHrefForState, - }); - - const wrapper = shallow(); - - expect(createHrefForState).toHaveBeenCalledTimes(0); - - wrapper.find(Dummy).props().createURL({ query: 'hello world' }); - - expect(createHrefForState).toHaveBeenCalledTimes(1); - expect(createHrefForState).toHaveBeenCalledWith({ - props: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - next: { - query: 'hello world', - }, - }); - }); - }); - - describe('searchForFacetValues', () => { - it('passes a searchForItems method to the component', () => { - const searchForFacetValues = (props, searchState, next) => ({ - props, - searchState, - next, - }); - - const Dummy = () => null; - const Connected = createConnectorWithoutContext({ - displayName: 'Connector', - getProvidedProps: () => {}, - searchForFacetValues, - })(Dummy); - - const onSearchForFacetValues = jest.fn(); - - const props = { - hello: 'there', - }; - - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - onSearchForFacetValues, - }); - - const wrapper = shallow(); - - expect(onSearchForFacetValues).toHaveBeenCalledTimes(0); - - wrapper.find(Dummy).props().searchForItems({ - facetName: 'brand', - query: 'apple', - maxFacetHits: 10, - }); - - expect(onSearchForFacetValues).toHaveBeenCalledTimes(1); - expect(onSearchForFacetValues).toHaveBeenCalledWith({ - props: { - hello: 'there', - contextValue: context, - }, - searchState: { - query: 'hello', - }, - next: { - facetName: 'brand', - query: 'apple', - maxFacetHits: 10, - }, - }); - }); - }); - - describe('wrapped with InstantSearchProvider', () => { - it('default export reads from context', () => { - const state = createFakeState({ - widgets: { - query: 'hello', - }, - }); - - const context = createFakeContext({ - store: createFakeStore({ - getState: () => state, - }), - }); - - const Dummy = (props) => JSON.stringify(props, null, 2).replace(/"/g, ''); - - const Connected = createConnector({ - displayName: 'Connector', - getProvidedProps: (props) => ({ providedProps: props }), - })(Dummy); - - const props = { - message: 'hello', - }; - - const wrapper = mount( - - - - ); - - expect(wrapper.text()).toMatchInlineSnapshot(` - "{ - message: hello, - providedProps: { - contextValue: { - store: {}, - widgetsManager: {} - }, - message: hello - } - }" - `); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.derived.js b/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.derived.js deleted file mode 100644 index d2779a05cb..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.derived.js +++ /dev/null @@ -1,699 +0,0 @@ -import { wait } from '@instantsearch/testutils'; - -import createInstantSearchManager from '../createInstantSearchManager'; - -const createSearchClient = () => ({ - search: jest.fn((requests) => - Promise.resolve({ - results: requests.map( - ({ indexName, params: { page, query, hitsPerPage } }) => ({ - index: indexName, - query, - page, - hitsPerPage, - hits: [], - }) - ), - }) - ), - searchForFacetValues() { - return Promise.resolve([ - { - facetHits: [], - }, - ]); - }, -}); - -describe('createInstantSearchManager with multi index', () => { - it('updates the store and searches', async () => { - // - // - // - // - // - // - // - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('first query 1'), - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setPage(3), - props: { - indexContextValue: { - targetedIndex: 'first', - }, - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('second query 1'), - props: { - indexContextValue: { - targetedIndex: 'second', - }, - }, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - expect(ism.store.getState().results.first).toEqual( - expect.objectContaining({ - query: 'first query 1', - index: 'first', - page: 3, - }) - ); - - expect(ism.store.getState().results.second).toEqual( - expect.objectContaining({ - query: 'second query 1', - index: 'second', - }) - ); - - await wait(0); - - // - ism.widgetsManager.getWidgets()[0].getSearchParameters = (params) => - params.setQuery('first query 2'); - - // - // - // - ism.widgetsManager.getWidgets()[4].getSearchParameters = (params) => - params.setQuery('second query 2'); - - ism.widgetsManager.update(); - - await wait(0); - - expect(ism.store.getState().results.first).toEqual( - expect.objectContaining({ - query: 'first query 2', - index: 'first', - page: 3, - }) - ); - - expect(ism.store.getState().results.second).toEqual( - expect.objectContaining({ - query: 'second query 2', - index: 'second', - }) - ); - }); - - // https://github.com/algolia/react-instantsearch/issues/2875 - it('update resultsState without mutate object', async () => { - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('first query 1'), - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setPage(3), - props: { - indexContextValue: { - targetedIndex: 'first', - }, - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('second query 1'), - props: { - indexContextValue: { - targetedIndex: 'second', - }, - }, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - const resultsWithFirstAndSecond = ism.store.getState().results; - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('thrid'), - props: { - indexName: 'thrid', - indexId: 'thrid', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('thrid query 1'), - props: { - indexContextValue: { - targetedIndex: 'thrid', - }, - }, - }); - - await wait(0); - - expect( - Object.is(resultsWithFirstAndSecond, ism.store.getState().results) - ).toBe(false); - }); - - it('searches with duplicate Index & SortBy', async () => { - // - // - // - // - // - // - // - // - // ; - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('query'), - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('third'), - props: { - indexContextValue: { - targetedIndex: 'first', - }, - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - expect(ism.store.getState().results.first).toEqual( - expect.objectContaining({ - index: 'third', - query: 'query', - }) - ); - - expect(ism.store.getState().results.second).toEqual( - expect.objectContaining({ - index: 'second', - query: 'query', - }) - ); - }); - - it('searches with N queries for N Index widgets', async () => { - // - // - // - // - // - // ; - - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('third'), - props: { - indexName: 'third', - indexId: 'third', - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('four'), - props: { - indexName: 'four', - indexId: 'four', - }, - }); - - await wait(0); - - expect(searchClient.search.mock.calls[0][0]).toHaveLength(4); - - ism.widgetsManager.update(); - - await wait(0); - - expect(searchClient.search.mock.calls[1][0]).toHaveLength(4); - }); - - it('searches with same index but different params', async () => { - // - // - // - // - // - // - // - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('first query'), - context: {}, - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first_5_hits', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => - params.setQueryParameter('hitsPerPage', 5), - props: { - indexContextValue: { - targetedIndex: 'first_5_hits', - }, - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first_10_hits', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => - params.setQueryParameter('hitsPerPage', 10), - props: { - indexContextValue: { - targetedIndex: 'first_10_hits', - }, - }, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - expect(ism.store.getState().results.first_5_hits).toEqual( - expect.objectContaining({ - query: 'first query', - index: 'first', - hitsPerPage: 5, - }) - ); - - expect(ism.store.getState().results.first_10_hits).toEqual( - expect.objectContaining({ - query: 'first query', - index: 'first', - hitsPerPage: 10, - }) - ); - }); - - it('switching from mono to multi index', async () => { - // - // - // - // - // - // - // - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('first query 1'), - props: {}, - }); - - // - const unregisterFirstIndexWidget = ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - // - // - const unregisterPaginationWidget = ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setPage(3), - props: { - indexContextValue: { - targetedIndex: 'first', - }, - }, - }); - - // - const unregisterSecondIndexWidget = ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - // - // - const unregisterSecondSearchBoxWidget = ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('second query 1'), - props: { - indexContextValue: { - targetedIndex: 'second', - }, - }, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - expect(ism.store.getState().results.first).toEqual( - expect.objectContaining({ - index: 'first', - query: 'first query 1', - page: 3, - }) - ); - - expect(ism.store.getState().results.second).toEqual( - expect.objectContaining({ - index: 'second', - query: 'second query 1', - }) - ); - - ism.widgetsManager.getWidgets()[0].getSearchParameters = (params) => - params.setQuery('first query 2'); - - unregisterFirstIndexWidget(); - unregisterPaginationWidget(); - unregisterSecondIndexWidget(); - unregisterSecondSearchBoxWidget(); - - await wait(0); - - expect(ism.store.getState().results).toEqual( - expect.objectContaining({ - index: 'first', - query: 'first query 2', - }) - ); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setPage(3), - props: { - indexContextValue: { - targetedIndex: 'first', - }, - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('second query 2'), - props: { - indexContextValue: { - targetedIndex: 'second', - }, - }, - }); - - await wait(0); - - expect(ism.store.getState().results.first).toEqual( - expect.objectContaining({ - index: 'first', - query: 'first query 2', - page: 3, - }) - ); - - expect(ism.store.getState().results.second).toEqual( - expect.objectContaining({ - index: 'second', - query: 'second query 2', - }) - ); - }); - - it('sets state with correct value for `searching` property', async () => { - // - // - // - // - // ; - - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'first', - initialState: {}, - searchParameters: {}, - searchClient, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('first query 1'), - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('first'), - props: { - indexName: 'first', - indexId: 'first', - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('second'), - props: { - indexName: 'second', - indexId: 'second', - }, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters: (x) => x.setIndex('third'), - props: { - indexName: 'third', - indexId: 'third', - }, - }); - - const setStateSpy = jest.spyOn(ism.store, 'setState'); - - await wait(0); - - expect(setStateSpy.mock.calls).toHaveLength(4); - expect(setStateSpy.mock.calls[0][0]).toEqual( - expect.objectContaining({ searching: true }) - ); - expect(setStateSpy.mock.calls[1][0]).toEqual( - expect.objectContaining({ searching: true }) - ); - expect(setStateSpy.mock.calls[2][0]).toEqual( - expect.objectContaining({ searching: true }) - ); - expect(setStateSpy.mock.calls[3][0]).toEqual( - expect.objectContaining({ searching: false }) - ); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.error.js b/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.error.js deleted file mode 100644 index bbc2cbbb37..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.error.js +++ /dev/null @@ -1,209 +0,0 @@ -import { wait } from '@instantsearch/testutils'; - -import createInstantSearchManager from '../createInstantSearchManager'; - -const createSearchClient = () => ({ - search: jest.fn(), - searchForFacetValues: jest.fn(), -}); - -describe('createInstantSearchManager with errors', () => { - describe('on search', () => { - it('updates the store on widget lifecycle', async () => { - const searchClient = createSearchClient({}); - - searchClient.search.mockImplementation(() => - Promise.reject(new Error('API_ERROR_1')) - ); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('search'), - context: {}, - props: {}, - }); - - expect(ism.store.getState().error).toBe(null); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - expect(ism.store.getState().error).toEqual(new Error('API_ERROR_1')); - expect(ism.store.getState().results).toEqual(null); - - searchClient.search.mockImplementation(() => - Promise.reject(new Error('API_ERROR_2')) - ); - - ism.widgetsManager.update(); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(2); - expect(ism.store.getState().error).toEqual(new Error('API_ERROR_2')); - expect(ism.store.getState().results).toEqual(null); - }); - - it('updates the store on external updates', async () => { - const searchClient = createSearchClient({}); - - searchClient.search.mockImplementation(() => - Promise.reject(new Error('API_ERROR_1')) - ); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.onExternalStateUpdate({}); - - expect(ism.store.getState().error).toBe(null); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - expect(ism.store.getState().error).toEqual(new Error('API_ERROR_1')); - expect(ism.store.getState().results).toEqual(null); - - searchClient.search.mockImplementation(() => - Promise.reject(new Error('API_ERROR_2')) - ); - - ism.onExternalStateUpdate({}); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(2); - expect(ism.store.getState().error).toEqual(new Error('API_ERROR_2')); - expect(ism.store.getState().results).toEqual(null); - }); - - it('reset the error after a successful search', async () => { - const searchClient = createSearchClient({}); - - searchClient.search.mockImplementation(() => - Promise.reject(new Error('API_ERROR')) - ); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('search'), - context: {}, - props: {}, - }); - - expect(ism.store.getState().error).toBe(null); - - await wait(0); - - expect(ism.store.getState().error).toEqual(new Error('API_ERROR')); - expect(ism.store.getState().results).toEqual(null); - - searchClient.search.mockImplementation(() => - Promise.resolve({ - results: [ - { - hits: [], - }, - ], - }) - ); - - ism.widgetsManager.update(); - - await wait(0); - - expect(ism.store.getState().error).toEqual(null); - expect(ism.store.getState().results).toEqual( - expect.objectContaining({ - hits: [], - }) - ); - }); - }); - - describe('on search for facet values', () => { - it('updates the store on function call', async () => { - const searchClient = createSearchClient({}); - - searchClient.searchForFacetValues.mockImplementation(() => - Promise.reject(new Error('API_ERROR')) - ); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - }); - - expect(ism.store.getState().searchingForFacetValues).toBe(true); - expect(ism.store.getState().error).toBe(null); - - await wait(0); - - expect(ism.store.getState().searchingForFacetValues).toBe(false); - expect(ism.store.getState().error).toEqual(new Error('API_ERROR')); - }); - - it('reset the error after a successful search', async () => { - const searchClient = createSearchClient({}); - - searchClient.searchForFacetValues.mockImplementation(() => - Promise.reject(new Error('API_ERROR')) - ); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - }); - - expect(ism.store.getState().error).toBe(null); - - await wait(0); - - expect(ism.store.getState().error).toEqual(new Error('API_ERROR')); - expect(ism.store.getState().resultsFacetValues).toBeUndefined(); - - searchClient.searchForFacetValues.mockImplementation(() => - Promise.resolve([ - { - facetHits: [], - }, - ]) - ); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - }); - - await wait(0); - - expect(ism.store.getState().error).toBe(null); - expect(ism.store.getState().resultsFacetValues).toEqual( - expect.objectContaining({ - facetName: [], - query: 'query', - }) - ); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.js b/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.js deleted file mode 100644 index a27a2c3b80..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.js +++ /dev/null @@ -1,997 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { runAllMicroTasks } from '@instantsearch/testutils'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import { SearchResults } from 'algoliasearch-helper'; -import algoliasearch from 'algoliasearch/lite'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import { - InstantSearch, - Index, - SortBy, - Configure, -} from 'react-instantsearch-dom'; - -import createInstantSearchManager from '../createInstantSearchManager'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.useFakeTimers(); - -const runOnlyNextMicroTask = () => Promise.resolve(); - -const createSearchClient = () => ({ - search: jest.fn(() => - Promise.resolve({ - results: [ - { - params: 'query=&hitsPerPage=10&page=0&facets=%5B%5D&tagFilters=', - page: 0, - hits: [], - hitsPerPage: 10, - nbPages: 0, - processingTimeMS: 4, - query: '', - nbHits: 0, - index: 'index', - }, - ], - }) - ), -}); - -describe('createInstantSearchManager', () => { - it('initializes the manager with an empty state', () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - expect(ism.store.getState()).toEqual({ - error: null, - isSearchStalled: true, - metadata: [], - results: null, - searching: false, - searchingForFacetValues: false, - widgets: {}, - }); - - expect(ism.widgetsManager.getWidgets()).toEqual([]); - - expect(ism.transitionState({})).toEqual({}); - - expect(ism.getWidgetsIds()).toEqual([]); - }); - - describe('client hydratation', () => { - it('hydrates the `searchClient` for a single index results', () => { - const searchClient = algoliasearch('appId', 'apiKey', { - _cache: true, // cache is not enabled by default inside Node - }); - - // Skip this test with Algoliasearch API Client >= v4 - // (cache is handled by the client ifself) - if (searchClient.transporter) { - return; - } - - const resultsState = { - metadata: [], - rawResults: [ - { - index: 'index', - query: 'query', - }, - ], - state: { - index: 'index', - query: 'query', - }, - }; - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(Object.keys(searchClient.cache)).toHaveLength(1); - Object.keys(searchClient.cache).forEach((key) => { - expect(typeof searchClient.cache[key]).toBe('string'); - expect(JSON.parse(searchClient.cache[key])).toEqual({ - results: [ - { - index: 'index', - query: 'query', - }, - ], - }); - }); - }); - - it('hydrates the `searchClient` for a multi index results', () => { - const searchClient = algoliasearch('appId', 'apiKey', { - _cache: true, // cache is not enabled by default inside Node - }); - - // Skip this test with Algoliasearch API Client >= v4 - // (cache is handled by the client ifself) - if (searchClient.transporter) { - return; - } - - const resultsState = { - metadata: [], - results: [ - { - _internalIndexId: 'index1', - rawResults: [ - { - index: 'index1', - query: 'query1', - }, - ], - state: { - index: 'index1', - query: 'query1', - }, - }, - { - _internalIndexId: 'index2', - rawResults: [ - { - index: 'index2', - query: 'query2', - }, - ], - state: { - index: 'index2', - query: 'query2', - }, - }, - ], - }; - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(Object.keys(searchClient.cache)).toHaveLength(1); - Object.keys(searchClient.cache).forEach((key) => { - expect(typeof searchClient.cache[key]).toBe('string'); - expect(JSON.parse(searchClient.cache[key])).toEqual({ - results: [ - { - index: 'index1', - query: 'query1', - }, - { - index: 'index2', - query: 'query2', - }, - ], - }); - }); - }); - - it('does not hydrate the `searchClient` without results', () => { - const searchClient = algoliasearch('appId', 'apiKey'); - - // Skip this test with Algoliasearch API Client >= v4 - // (cache is handled by the client ifself) - if (searchClient.transporter) { - return; - } - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - - createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - }); - - it("does not hydrate the `searchClient` if it's not an Algolia client", () => { - const searchClient = { - _useCache: true, - cache: {}, - }; - - // Skip this test with Algoliasearch API Client >= v4 - // (cache is handled by the client ifself) - if (searchClient.transporter) { - return; - } - - const resultsState = { - metadata: [], - rawResults: [ - { - index: 'indexName', - query: 'query', - }, - ], - state: { - index: 'indexName', - query: 'query', - }, - }; - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - }); - - it('does not hydrate the `searchClient` without cache enabled', () => { - const searchClient = algoliasearch('appId', 'apiKey', { - _cache: false, - }); - - // Skip this test with Algoliasearch API Client >= v4 - // (cache is handled by the client ifself) - if (searchClient.transporter) { - return; - } - - const resultsState = { - metadata: [], - rawResults: [ - { - index: 'indexName', - query: 'query', - }, - ], - state: { - index: 'indexName', - query: 'query', - }, - }; - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(Object.keys(searchClient.cache)).toHaveLength(0); - }); - - it('when using algoliasearch@v4, it overrides search only once', () => { - const searchClient = algoliasearch('appId', 'apiKey', { - _cache: true, - }); - - // Skip this test with Algoliasearch API Client < v4, as - // search does not need to be overridden. - if (!searchClient.transporter) { - return; - } - - const resultsState = { - metadata: [], - rawResults: [ - { - index: 'indexName', - query: 'query', - }, - ], - state: { - index: 'indexName', - query: 'query', - }, - }; - - const originalSearch = algoliasearch.search; - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(searchClient.search).not.toBe(originalSearch); - - const alreadyOverridden = jest.fn(); - searchClient.search = alreadyOverridden; - - createInstantSearchManager({ - indexName: 'index', - searchClient, - resultsState, - }); - - expect(searchClient.search).toBe(alreadyOverridden); - }); - }); - - describe('results hydration', () => { - it('initializes the manager with a single index hydrated results', () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - resultsState: { - metadata: [], - rawResults: [ - { - index: 'indexName', - query: 'query', - }, - ], - state: { - index: 'indexName', - query: 'query', - }, - }, - }); - - expect(ism.store.getState().results).toBeInstanceOf(SearchResults); - expect(ism.store.getState().results.query).toEqual('query'); - }); - - it('initializes the manager with a multi index hydrated results', () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - resultsState: { - metadata: [], - results: [ - { - _internalIndexId: 'index1', - rawResults: [ - { - index: 'index1', - query: 'query1', - }, - ], - state: { - index: 'index1', - query: 'query1', - }, - }, - { - _internalIndexId: 'index2', - rawResults: [ - { - index: 'index2', - query: 'query2', - }, - ], - state: { - index: 'index2', - query: 'query2', - }, - }, - ], - }, - }); - - expect(ism.store.getState().results.index1.query).toBe('query1'); - expect(ism.store.getState().results.index1).toBeInstanceOf(SearchResults); - expect(ism.store.getState().results.index2.query).toBe('query2'); - expect(ism.store.getState().results.index2).toBeInstanceOf(SearchResults); - }); - }); - - describe('metadata hydration', () => { - test('replaces value with a function returning empty search state', () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - resultsState: { - metadata: [ - { stuff: 1, items: [{ stuff: 2, items: [{ stuff: 3 }] }] }, - ], - rawResults: [ - { - index: 'indexName', - query: 'query', - }, - ], - state: { - index: 'indexName', - query: 'query', - }, - }, - }); - - const hydratedMetadata = ism.store.getState().metadata; - - expect(hydratedMetadata).toEqual([ - { - value: expect.any(Function), - stuff: 1, - items: [ - { - value: expect.any(Function), - stuff: 2, - items: [ - { - value: expect.any(Function), - stuff: 3, - }, - ], - }, - ], - }, - ]); - - expect(hydratedMetadata[0].value()).toEqual({}); - expect(hydratedMetadata[0].items[0].value()).toEqual({}); - expect(hydratedMetadata[0].items[0].items[0].value()).toEqual({}); - }); - }); - - describe('widget manager', () => { - it('triggers a search when a widget is added', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getSearchParameters: () => ({}), - props: {}, - context: {}, - }); - - expect(ism.store.getState().searching).toBe(false); - - await runOnlyNextMicroTask(); - - expect(ism.store.getState().searching).toBe(true); - - await runAllMicroTasks(); - - expect(ism.store.getState().searching).toBe(false); - }); - }); - - describe('transitionState', () => { - it('executes widgets hook', () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - ism.widgetsManager.registerWidget({ - transitionState: (next, current) => { - expect(next).toEqual({}); - - return { - ...current, - a: 1, - }; - }, - }); - - ism.widgetsManager.registerWidget({ - transitionState: (next, current) => { - expect(next).toEqual({}); - - return { - ...current, - b: 2, - }; - }, - }); - - expect(ism.transitionState()).toEqual({ - a: 1, - b: 2, - }); - }); - }); - - describe('getWidgetsIds', () => { - it('returns the list of ids of all registered widgets', async () => { - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - expect(ism.getWidgetsIds()).toEqual([]); - - ism.widgetsManager.registerWidget({ getMetadata: () => ({ id: 'a' }) }); - ism.widgetsManager.registerWidget({ getMetadata: () => ({ id: 'b' }) }); - ism.widgetsManager.registerWidget({ getMetadata: () => ({ id: 'c' }) }); - ism.widgetsManager.registerWidget({ getMetadata: () => ({ id: 'd' }) }); - - await runAllMicroTasks(); - - expect(ism.getWidgetsIds()).toEqual(['a', 'b', 'c', 'd']); - }); - }); - - describe('getSearchParameters', () => { - it('expects a widget top level to be shared between main and derived parameters', () => { - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setQuery('shared'); - }, - context: {}, - props: {}, - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setIndex('main'); - }, - props: { - indexId: 'main', - }, - }); - - const { mainParameters, derivedParameters } = ism.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index', - query: 'shared', - }) - ); - - expect(derivedParameters).toEqual([ - { - indexId: 'main', - parameters: expect.objectContaining({ - index: 'main', - query: 'shared', - }), - }, - ]); - }); - - it('expects a widget with the same id than the indexName to be a main parameters', () => { - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setIndex('main'); - }, - context: {}, - props: { - indexId: 'index', - }, - }); - - const { mainParameters, derivedParameters } = ism.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'main', - }) - ); - - expect(derivedParameters).toEqual([]); - }); - - it('expects a widget with a different id than the indexName to be a derived parameters', () => { - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setIndex('main'); - }, - context: {}, - props: { - indexId: 'index_main', - }, - }); - - const { mainParameters, derivedParameters } = ism.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index', - }) - ); - - expect(derivedParameters).toEqual([ - { - indexId: 'index_main', - parameters: expect.objectContaining({ - index: 'main', - }), - }, - ]); - }); - - it('expects a widget within a mutli index context with the same id than the indexName to be a main parameters', () => { - // - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setIndex('index'); - }, - context: {}, - props: { - indexId: 'index', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setQuery('main'); - }, - context: { - multiIndexContext: { - targetedIndex: 'index', - }, - }, - props: {}, - }); - - const { mainParameters, derivedParameters } = ism.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index', - query: 'main', - }) - ); - - expect(derivedParameters).toEqual([]); - }); - - it('expects a widget within a mutli index context with a different id than the indexName to be a derived parameters', () => { - // - // - // - // - // - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient: createSearchClient({}), - }); - - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setIndex('index'); - }, - props: { - indexId: 'index_with_refinement', - }, - }); - - // - // - // - ism.widgetsManager.registerWidget({ - getSearchParameters(state) { - return state.setQuery('derived'); - }, - props: { - indexContextValue: { - targetedIndex: 'index_with_refinement', - }, - }, - }); - - const { mainParameters, derivedParameters } = ism.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index', - }) - ); - - expect(derivedParameters).toEqual([ - { - indexId: 'index_with_refinement', - parameters: expect.objectContaining({ - index: 'index', - query: 'derived', - }), - }, - ]); - }); - - it('expects widgets main parameters and derived parameters to be correctly calculated within a multi index context', () => { - const wrapper = mount( - - - - - - - - - - - - - - - - - ); - - const { mainParameters, derivedParameters } = wrapper - .instance() - .state.instantSearchManager.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index1', - }) - ); - - expect(derivedParameters).toEqual([ - expect.objectContaining({ - indexId: 'bestbuy', - parameters: expect.objectContaining({ - index: 'bestbuy', - }), - }), - expect.objectContaining({ - indexId: 'instant_search', - parameters: expect.objectContaining({ - index: 'instant_search', - }), - }), - expect.objectContaining({ - indexId: 'instant_search_apple', - parameters: expect.objectContaining({ - index: 'instant_search', - filters: 'brand:Apple', - }), - }), - expect.objectContaining({ - indexId: 'instant_search_samsung', - parameters: expect.objectContaining({ - index: 'instant_search', - filters: 'brand:Samsung', - }), - }), - expect.objectContaining({ - indexId: 'instant_search_microsoft', - parameters: expect.objectContaining({ - index: 'instant_search', - filters: 'brand:Microsoft', - }), - }), - ]); - }); - - it('expects widgets main parameters and derived parameters to be correctly calculated with SortBy within a multi index context', () => { - const wrapper = mount( - - - - - - - - - - ); - - const { mainParameters, derivedParameters } = wrapper - .instance() - .state.instantSearchManager.getSearchParameters(); - - expect(mainParameters).toEqual( - expect.objectContaining({ - index: 'index1', - }) - ); - - expect(derivedParameters).toEqual([ - expect.objectContaining({ - indexId: 'categories', - parameters: expect.objectContaining({ - index: 'bestbuy', - }), - }), - expect.objectContaining({ - indexId: 'products', - parameters: expect.objectContaining({ - index: 'brands', - }), - }), - ]); - }); - }); - - describe('searchStalled', () => { - it('should be updated if search is stalled', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getMetadata: () => {}, - transitionState: () => {}, - }); - - expect(searchClient.search).not.toHaveBeenCalled(); - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: true, - }); - - await runOnlyNextMicroTask(); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: true, - }); - - jest.runAllTimers(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: true, - }); - - await runOnlyNextMicroTask(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: false, - }); - - ism.widgetsManager.update(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: false, - }); - - await runOnlyNextMicroTask(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: false, - }); - - jest.runAllTimers(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: true, - }); - - await runOnlyNextMicroTask(); - - expect(ism.store.getState()).toMatchObject({ - isSearchStalled: false, - }); - }); - }); - - describe('client.search', () => { - it('should be called when there is a new widget', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getMetadata: () => {}, - transitionState: () => {}, - }); - - expect(searchClient.search).toHaveBeenCalledTimes(0); - - await runAllMicroTasks(); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - }); - - it('should be called when there is a new client', () => { - const searchClient = createSearchClient({}); - const nextSearchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - expect(searchClient.search).toHaveBeenCalledTimes(0); - expect(nextSearchClient.search).toHaveBeenCalledTimes(0); - - ism.updateClient(nextSearchClient); - - expect(searchClient.search).toHaveBeenCalledTimes(0); - expect(nextSearchClient.search).toHaveBeenCalledTimes(1); - }); - - it('should not be called when the search is skipped', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.skipSearch(); - - ism.widgetsManager.registerWidget({ - getMetadata: () => {}, - transitionState: () => {}, - }); - - await runAllMicroTasks(); - - expect(searchClient.search).toHaveBeenCalledTimes(0); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.result.js b/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.result.js deleted file mode 100644 index 487ae7207b..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createInstantSearchManager.result.js +++ /dev/null @@ -1,244 +0,0 @@ -import { wait } from '@instantsearch/testutils'; - -import createInstantSearchManager from '../createInstantSearchManager'; - -const createSearchClient = () => ({ - search: jest.fn(() => - Promise.resolve({ - results: [ - { - hits: [{ value: 'results' }], - }, - ], - }) - ), - searchForFacetValues: jest.fn(() => - Promise.resolve([ - { - facetHits: [{ value: 'results' }], - }, - ]) - ), -}); - -describe('createInstantSearchManager with results', () => { - describe('on search', () => { - it('updates the store on widget lifecycle', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.setQuery('search'), - props: {}, - context: {}, - }); - - expect(ism.store.getState().results).toBe(null); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - expect(ism.store.getState().results.hits).toEqual([{ value: 'results' }]); - expect(ism.store.getState().error).toBe(null); - - ism.widgetsManager.update(); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(2); - expect(ism.store.getState().results.hits).toEqual([{ value: 'results' }]); - expect(ism.store.getState().error).toBe(null); - }); - - it('updates the store on external updates', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - ism.onExternalStateUpdate({}); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(1); - expect(ism.store.getState().results.hits).toEqual([{ value: 'results' }]); - expect(ism.store.getState().error).toBe(null); - - ism.onExternalStateUpdate({}); - - await wait(0); - - expect(searchClient.search).toHaveBeenCalledTimes(2); - expect(ism.store.getState().results.hits).toEqual([{ value: 'results' }]); - expect(ism.store.getState().error).toBe(null); - }); - }); - - describe('on search for facet values', () => { - // We should avoid to rely on such mock, we mostly do an integration tests rather than - // a unit ones for the manager. We have to simulate a real helper environement (facet, - // etc, ...) to have something that don't throw errors. An easier way would be to provide - // the helper to the manager with the real implementation by default. With this, we can easily - // pass a custom helper (mocked or not) and don't rely on the helper + client. - - it('updates the store and searches', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - // We have to register the facet to be able to search on it - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.addFacet('facetName'), - props: {}, - context: {}, - }); - - await wait(0); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - }); - - expect(ism.store.getState().searchingForFacetValues).toBe(true); - - await wait(0); - - expect(ism.store.getState().searchingForFacetValues).toBe(false); - - expect(searchClient.searchForFacetValues).toHaveBeenCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - params: expect.objectContaining({ - facetName: 'facetName', - facetQuery: 'query', - maxFacetHits: 10, - }), - }), - ]) - ); - - expect(ism.store.getState().resultsFacetValues).toEqual({ - facetName: [expect.objectContaining({ value: 'results' })], - query: 'query', - }); - }); - - it('updates the store and searches with maxFacetHits', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - // We have to register the facet to be able to search on it - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.addFacet('facetName'), - props: {}, - context: {}, - }); - - await wait(0); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - maxFacetHits: 25, - }); - - await wait(0); - - expect(searchClient.searchForFacetValues).toHaveBeenCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - params: expect.objectContaining({ - maxFacetHits: 25, - }), - }), - ]) - ); - }); - - it('updates the store and searches with maxFacetHits out of range (higher)', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - // We have to register the facet to be able to search on it - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.addFacet('facetName'), - props: {}, - context: {}, - }); - - await wait(0); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - maxFacetHits: 125, - }); - - await wait(0); - - expect(searchClient.searchForFacetValues).toHaveBeenCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - params: expect.objectContaining({ - maxFacetHits: 100, - }), - }), - ]) - ); - }); - - it('updates the store and searches with maxFacetHits out of range (lower)', async () => { - const searchClient = createSearchClient({}); - - const ism = createInstantSearchManager({ - indexName: 'index', - searchClient, - }); - - // We have to register the facet to be able to search on it - ism.widgetsManager.registerWidget({ - getSearchParameters: (params) => params.addFacet('facetName'), - props: {}, - context: {}, - }); - - await wait(0); - - ism.onSearchForFacetValues({ - facetName: 'facetName', - query: 'query', - maxFacetHits: 0, - }); - - await wait(0); - - expect(searchClient.searchForFacetValues).toHaveBeenCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - params: expect.objectContaining({ - maxFacetHits: 1, - }), - }), - ]) - ); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createStore.js b/packages/react-instantsearch-core/src/core/__tests__/createStore.js deleted file mode 100644 index 741926aea6..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createStore.js +++ /dev/null @@ -1,49 +0,0 @@ -import createStore from '../createStore'; - -describe('createStore', () => { - describe('getState', () => { - it('retrieves the current state of the store', () => { - const initialState = {}; - const store = createStore(initialState); - expect(store.getState()).toBe(initialState); - }); - }); - - describe('setState', () => { - it('sets a new state', () => { - const initialState = {}; - const store = createStore(initialState); - const newState = {}; - store.setState(newState); - expect(store.getState()).toBe(newState); - }); - }); - - describe('subscribe', () => { - it('subscribes to new states', () => { - const initialState = {}; - const store = createStore(initialState); - const listener = jest.fn(); - store.subscribe(listener); - const newState = {}; - expect(listener.mock.calls).toHaveLength(0); - store.setState(newState); - expect(listener.mock.calls).toHaveLength(1); - }); - - it('returns a method to unsubscribe', () => { - const initialState = {}; - const store = createStore(initialState); - const listener = jest.fn(); - const unsubscribe = store.subscribe(listener); - const newState = {}; - expect(listener.mock.calls).toHaveLength(0); - store.setState(newState); - expect(listener.mock.calls).toHaveLength(1); - unsubscribe(); - const newerState = {}; - store.setState(newerState); - expect(listener.mock.calls).toHaveLength(1); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/createWidgetsManager.js b/packages/react-instantsearch-core/src/core/__tests__/createWidgetsManager.js deleted file mode 100644 index bef1cd171d..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/createWidgetsManager.js +++ /dev/null @@ -1,39 +0,0 @@ -import createWidgetsManager from '../createWidgetsManager'; - -describe('createWidgetsManager', () => { - describe('registerWidget', () => { - it('adds the widget to the widgets list', () => { - const wm = createWidgetsManager(() => null); - const widget = {}; - wm.registerWidget(widget); - expect(wm.getWidgets()[0]).toBe(widget); - }); - - it('returns an unregister method', () => { - const wm = createWidgetsManager(() => null); - const unregister = wm.registerWidget({}); - unregister(); - expect(wm.getWidgets()).toHaveLength(0); - }); - - it('schedules an update', () => { - const onUpdate = jest.fn(); - const wm = createWidgetsManager(onUpdate); - wm.registerWidget({}); - return Promise.resolve().then(() => { - expect(onUpdate.mock.calls).toHaveLength(1); - }); - }); - }); - - describe('update', () => { - it('schedules an update', () => { - const onUpdate = jest.fn(); - const wm = createWidgetsManager(onUpdate); - wm.update(); - return Promise.resolve().then(() => { - expect(onUpdate.mock.calls).toHaveLength(1); - }); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/highlight.js b/packages/react-instantsearch-core/src/core/__tests__/highlight.js deleted file mode 100644 index 832070fb5d..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/highlight.js +++ /dev/null @@ -1,148 +0,0 @@ -import { parseAlgoliaHit } from '../highlight'; - -describe('parseAlgoliaHit()', () => { - it('does not break when there is a missing attribute', () => { - const attribute = 'attr'; - const out = parseAlgoliaHit({ - attribute, - hit: {}, - highlightProperty: '_highlightResult', - }); - expect(out).toEqual([]); - }); - - it('creates a single element when there is no tag', () => { - const value = 'foo bar baz'; - const attribute = 'attr'; - const out = parseAlgoliaHit({ - attribute, - hit: createHit(attribute, value), - highlightProperty: '_highlightResult', - }); - expect(out).toEqual([{ isHighlighted: false, value }]); - }); - - it('creates a single element when there is only a tag', () => { - const textValue = 'foo bar baz'; - const value = `${textValue}`; - const attribute = 'attr'; - const out = parseAlgoliaHit({ - attribute, - hit: createHit(attribute, value), - highlightProperty: '_highlightResult', - }); - expect(out).toEqual([{ value: textValue, isHighlighted: true }]); - }); - - it('fetches and parses a deep attribute', () => { - const textValue = 'foo bar baz'; - const value = `${textValue}`; - const hit = { - lvl0: { lvl1: { lvl2: value } }, - _highlightResult: { - lvl0: { lvl1: { lvl2: { value } } }, - }, - }; - const out = parseAlgoliaHit({ - attribute: 'lvl0.lvl1.lvl2', - hit, - highlightProperty: '_highlightResult', - }); - expect(out).toEqual([{ value: textValue, isHighlighted: true }]); - }); - - it('parses the string and returns the part that are highlighted - 1 big highlight', () => { - const str = 'like algolia does algolia'; - const hit = createHit('attr', str); - const parsed = parseAlgoliaHit({ - attribute: 'attr', - hit, - highlightProperty: '_highlightResult', - }); - expect(parsed).toEqual([ - { value: 'like ', isHighlighted: false }, - { value: 'al', isHighlighted: true }, - { value: 'golia does ', isHighlighted: false }, - { value: 'al', isHighlighted: true }, - { value: 'golia', isHighlighted: false }, - ]); - }); - - it('supports the array format, parses it and returns the part that is highlighted', () => { - const hit = { - tags: ['litterature', 'biology', 'photography'], - _highlightResult: { - tags: [ - { value: 'litterature' }, - { value: 'biology' }, - { value: 'photography' }, - ], - }, - }; - - const actual = parseAlgoliaHit({ - attribute: 'tags', - hit, - highlightProperty: '_highlightResult', - }); - - const exepectation = [ - [{ value: 'litterature', isHighlighted: false }], - [{ value: 'biology', isHighlighted: false }], - [ - { value: 'photo', isHighlighted: true }, - { value: 'graphy', isHighlighted: false }, - ], - ]; - - expect(actual).toEqual(exepectation); - }); - - it('parses the string and returns the part that are highlighted - same pre and post tag', () => { - const str = 'surpise **lo**l mouhahah roflmao **lo**utre'; - const hit = createHit('attr', str); - const parsed = parseAlgoliaHit({ - preTag: '**', - postTag: '**', - attribute: 'attr', - hit, - highlightProperty: '_highlightResult', - }); - expect(parsed).toEqual([ - { value: 'surpise ', isHighlighted: false }, - { value: 'lo', isHighlighted: true }, - { value: 'l mouhahah roflmao ', isHighlighted: false }, - { value: 'lo', isHighlighted: true }, - { value: 'utre', isHighlighted: false }, - ]); - }); - - it('throws when hit is `null`', () => { - expect( - parseAlgoliaHit.bind(null, { - attribute: 'unknownattribute', - hit: null, - highlightProperty: '_highlightResult', - }) - ).toThrow('`hit`, the matching record, must be provided'); - }); - - it('throws when hit is `undefined`', () => { - expect( - parseAlgoliaHit.bind(null, { - attribute: 'unknownAttribute', - hit: undefined, - highlightProperty: '_highlightResult', - }) - ).toThrow('`hit`, the matching record, must be provided'); - }); -}); - -function createHit(attribute, value) { - return { - [attribute]: value, - _highlightResult: { - [attribute]: { value }, - }, - }; -} diff --git a/packages/react-instantsearch-core/src/core/__tests__/indexUtils.js b/packages/react-instantsearch-core/src/core/__tests__/indexUtils.js deleted file mode 100644 index a0c564d6a7..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/indexUtils.js +++ /dev/null @@ -1,756 +0,0 @@ -import { - refineValue, - getCurrentRefinementValue, - cleanUpValue, - getResults, -} from '../indexUtils'; - -describe('utility method for manipulating the search state', () => { - describe('when there is a single index', () => { - const context = { ais: { mainTargetedIndex: 'index' } }; - it('refine with no namespace', () => { - let searchState = {}; - let nextRefinement = { refinement: 'refinement' }; - let resetPage = false; - - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - expect(searchState).toEqual({ refinement: 'refinement' }); - - nextRefinement = { another: 'another' }; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - expect(searchState).toEqual({ - refinement: 'refinement', - another: 'another', - }); - - nextRefinement = { last: 'last' }; - resetPage = true; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - expect(searchState).toEqual({ - page: 1, - last: 'last', - refinement: 'refinement', - another: 'another', - }); - }); - - it('refine with namespace', () => { - let searchState = {}; - let nextRefinement = { refinement: 'refinement' }; - let resetPage = false; - - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ namespace: { refinement: 'refinement' } }); - - nextRefinement = { another: 'another' }; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ - namespace: { refinement: 'refinement', another: 'another' }, - }); - - nextRefinement = { another: 'another' }; - resetPage = true; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ - page: 1, - namespace: { refinement: 'refinement', another: 'another' }, - }); - }); - - describe('getCurrentRefinementValue', () => { - it('retrieves the current refinement value', () => { - const searchState = { - page: 1, - last: 'last', - refinement: 'refinement', - another: 'another', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }; - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.another', - null - ) - ).toEqual('another'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.nested.another', - null - ) - ).toEqual('nested.another'); - }); - - it('retrieves default value', () => { - expect( - getCurrentRefinementValue( - {}, - {}, - context, - 'refinement', - 'defaultValue' - ) - ).toEqual('defaultValue'); - - expect( - getCurrentRefinementValue( - { defaultRefinement: 'defaultRefinement' }, - {}, - context, - 'refinement', - null - ) - ).toEqual('defaultRefinement'); - }); - - it('retrieves from objects without prototype', () => { - const searchState = Object.create(null); - searchState.page = 1; - searchState.last = 'last'; - searchState.refinement = 'refinement'; - searchState.another = 'another'; - searchState.namespace = { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }; - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.another', - null - ) - ).toEqual('another'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.nested.another', - null - ) - ).toEqual('nested.another'); - }); - }); - - it('clean up values', () => { - let searchState = { - page: 1, - last: 'last', - refinement: 'refinement', - another: 'another', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }; - - searchState = cleanUpValue(searchState, context, 'refinement'); - - expect(searchState).toEqual({ - page: 1, - last: 'last', - another: 'another', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }); - - searchState = cleanUpValue(searchState, context, 'namespace.another'); - - expect(searchState).toEqual({ - page: 1, - last: 'last', - another: 'another', - namespace: { - refinement: 'refinement', - 'nested.another': 'nested.another', - }, - }); - - searchState = cleanUpValue(searchState, context, 'namespace.refinement'); - - expect(searchState).toEqual({ - page: 1, - last: 'last', - another: 'another', - namespace: { 'nested.another': 'nested.another' }, - }); - - searchState = cleanUpValue( - searchState, - context, - 'namespace.nested.another' - ); - - expect(searchState).toEqual({ - page: 1, - last: 'last', - another: 'another', - namespace: {}, - }); - }); - - it('get results', () => { - const searchResults = { results: { hits: ['some'] } }; - - const results = getResults(searchResults, context); - - expect(results).toEqual({ hits: ['some'] }); - }); - }); - - describe('when there are multiple index', () => { - let context = { multiIndexContext: { targetedIndex: 'first' } }; - it('refine with no namespace', () => { - let searchState = {}; - let nextRefinement = { refinement: 'refinement' }; - - searchState = refineValue(searchState, nextRefinement, context); - - expect(searchState).toEqual({ - indices: { first: { refinement: 'refinement' } }, - }); - - nextRefinement = { another: 'another' }; - searchState = refineValue(searchState, nextRefinement, context); - - expect(searchState).toEqual({ - indices: { first: { refinement: 'refinement', another: 'another' } }, - }); - - nextRefinement = { last: 'last' }; - const resetPage = true; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - expect(searchState).toEqual({ - indices: { - first: { - page: 1, - refinement: 'refinement', - another: 'another', - last: 'last', - }, - }, - }); - }); - - it('refine with namespace', () => { - let searchState = {}; - let nextRefinement = { refinement: 'refinement' }; - let resetPage = false; - - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ - indices: { first: { namespace: { refinement: 'refinement' } } }, - }); - - nextRefinement = { another: 'another' }; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ - indices: { - first: { - page: 1, - namespace: { refinement: 'refinement', another: 'another' }, - }, - }, - }); - - nextRefinement = { another: 'another' }; - resetPage = true; - searchState = refineValue( - searchState, - nextRefinement, - context, - resetPage, - 'namespace' - ); - - expect(searchState).toEqual({ - indices: { - first: { - page: 1, - namespace: { refinement: 'refinement', another: 'another' }, - }, - }, - }); - }); - - describe('getCurrentRefinementValue', () => { - it('retrieves the current refinement value', () => { - const searchState = { - page: 1, - refinement: 'refinement', - indices: { - first: { - refinement: 'refinement', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }, - }, - }; - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.another', - null - ) - ).toEqual('another'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.nested.another', - null - ) - ).toEqual('nested.another'); - - expect( - getCurrentRefinementValue( - {}, - {}, - context, - 'refinement', - 'defaultValue' - ) - ).toEqual('defaultValue'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'anotherNamespace.refinement.top', - 'defaultValue' - ) - ).toEqual('defaultValue'); - - expect( - getCurrentRefinementValue( - { defaultRefinement: 'defaultRefinement' }, - {}, - context, - 'refinement', - null - ) - ).toEqual('defaultRefinement'); - }); - - it('retrieves default value', () => { - const searchState = { - page: 1, - refinement: 'refinement', - indices: {}, - }; - - const defaultRefinement = null; - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'refinement', - defaultRefinement - ) - ).toBe(defaultRefinement); - }); - - it('retrieves from objects without prototype', () => { - const searchState = Object.create(null); - - searchState.page = 1; - searchState.refinement = 'refinement'; - searchState.indices = { - first: { - refinement: 'refinement', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }, - }; - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.refinement', - null - ) - ).toEqual('refinement'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.another', - null - ) - ).toEqual('another'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'namespace.nested.another', - null - ) - ).toEqual('nested.another'); - - expect( - getCurrentRefinementValue( - {}, - {}, - context, - 'refinement', - 'defaultValue' - ) - ).toEqual('defaultValue'); - - expect( - getCurrentRefinementValue( - {}, - searchState, - context, - 'anotherNamespace.refinement.top', - 'defaultValue' - ) - ).toEqual('defaultValue'); - - expect( - getCurrentRefinementValue( - { defaultRefinement: 'defaultRefinement' }, - {}, - context, - 'refinement', - null - ) - ).toEqual('defaultRefinement'); - }); - }); - - it('clean up values', () => { - let searchState = { - page: 1, - indices: { - first: { - refinement: 'refinement', - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }, - }, - }; - - searchState = cleanUpValue(searchState, context, 'refinement'); - - expect(searchState).toEqual({ - page: 1, - indices: { - first: { - namespace: { - refinement: 'refinement', - another: 'another', - 'nested.another': 'nested.another', - }, - }, - }, - }); - - searchState = cleanUpValue(searchState, context, 'namespace.another'); - - expect(searchState).toEqual({ - page: 1, - indices: { - first: { - namespace: { - refinement: 'refinement', - 'nested.another': 'nested.another', - }, - }, - }, - }); - - searchState = cleanUpValue(searchState, context, 'namespace.refinement'); - - expect(searchState).toEqual({ - page: 1, - indices: { - first: { - namespace: { - 'nested.another': 'nested.another', - }, - }, - }, - }); - - searchState = cleanUpValue( - searchState, - context, - 'namespace.nested.another' - ); - - expect(searchState).toEqual({ - page: 1, - indices: { - first: { - namespace: {}, - }, - }, - }); - - // When nothing is refine the searchState doesn't have the indices - // attribute even if we are in a context with . This should - // not happen, the searchState should always be in sync (indices + no values). - searchState = { - page: 1, - }; - - searchState = cleanUpValue(searchState, context, 'namespace.refinement'); - - expect(searchState).toEqual({ - page: 1, - namespace: {}, - }); - - // It might happen that we try to cleanUp an index that is not - // present on the searchState. We should not throw an error in - // that case, just return the searchState as it is. - searchState = { - page: 1, - indices: { - second: { - page: 1, - }, - }, - }; - - searchState = cleanUpValue(searchState, context, 'menu.category'); - - expect(searchState).toEqual({ - page: 1, - indices: { - second: { - page: 1, - }, - }, - }); - }); - - it('get results', () => { - let searchResults = { results: { first: { some: 'results' } } }; - - let results = getResults(searchResults, context); - - expect(results).toEqual({ some: 'results' }); - - searchResults = { results: { first: { some: 'results' } } }; - - results = getResults(searchResults, { - ais: { mainTargetedIndex: 'first' }, - }); - - expect(results).toEqual({ some: 'results' }); - }); - - it('refine shared widgets should reset indices page to 1 with resetPage', () => { - context = {}; - const resetPage = true; - const nextRefinement = { query: 'new' }; - const searchState = { - indices: { - first: { page: 3 }, - second: { page: 3 }, - }, - }; - - const actual = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - const expectation = { - query: 'new', - page: 1, - indices: { - first: { page: 1 }, - second: { page: 1 }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('refine shared widgets should not reset indices page to 1 without resetPage', () => { - context = {}; - const resetPage = false; - const nextRefinement = { query: 'new' }; - const searchState = { - indices: { - first: { page: 3 }, - second: { page: 3 }, - }, - }; - - const actual = refineValue( - searchState, - nextRefinement, - context, - resetPage - ); - - const expectation = { - query: 'new', - indices: { - first: { page: 3 }, - second: { page: 3 }, - }, - }; - - expect(actual).toEqual(expectation); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/metadata.tsx b/packages/react-instantsearch-core/src/core/__tests__/metadata.tsx deleted file mode 100644 index 719ae17f5c..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/metadata.tsx +++ /dev/null @@ -1,259 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { render } from '@testing-library/react'; -import algoliasearch from 'algoliasearch/lite'; -import React from 'react'; - -import { connectSearchBox } from '../..'; -import { InstantSearchProvider } from '../context'; -import createStore from '../createStore'; -import createWidgetsManager from '../createWidgetsManager'; -import { isMetadataEnabled, getMetadataPayload } from '../metadata'; - -import type { SearchClient } from '../../widgets/InstantSearch'; - -const { window: originalWindow } = global; - -Object.defineProperty( - window.navigator, - 'userAgent', - ((value) => ({ - get() { - return value; - }, - set(v: string) { - value = v; - }, - }))(window.navigator.userAgent) -); - -const defaultUserAgent = - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15'; -const algoliaUserAgent = 'Algolia Crawler 5.3.2'; - -function setUserAgent(userAgent: string) { - // casting to any, as userAgent is set as readonly by TypeScript - (global.navigator as any).userAgent = userAgent; -} - -describe('isMetadataEnabled', () => { - afterEach(() => { - setUserAgent(defaultUserAgent); - global.window = originalWindow; - }); - - it('does not enable on normal user agent', () => { - setUserAgent(defaultUserAgent); - - expect(isMetadataEnabled()).toBe(false); - }); - - it("does not enable when there's no window", () => { - setUserAgent(algoliaUserAgent); - - // @ts-expect-error - delete global.window; - - expect(isMetadataEnabled()).toBe(false); - }); - - it("does not enable when there's no navigator (react native)", () => { - setUserAgent(algoliaUserAgent); - - // @ts-expect-error - delete global.window; - // @ts-expect-error - global.window = {}; - - expect(isMetadataEnabled()).toBe(false); - }); - - it('metadata enabled returns true', () => { - setUserAgent(algoliaUserAgent); - - expect(isMetadataEnabled()).toBe(true); - }); -}); - -describe('getMetadataPayload', () => { - describe('user agent', () => { - test('extracts user agent from algoliasearch', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = algoliasearch( - 'appId', - 'apiKey' - ) as unknown as SearchClient; - - const { ua } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(ua).toEqual( - expect.stringMatching( - /^Algolia for JavaScript \((\d+\.?)+\); Node\.js \((\d+\.?)+\)$/ - ) - ); - }); - - test('extracts user agent from algoliasearch v3', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = { - search() { - return Promise.resolve({}); - }, - searchForFacetValues() { - return Promise.resolve({}); - }, - _ua: 'v3 style user agent', - }; - - const { ua } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(ua).toEqual('v3 style user agent'); - }); - - test('extracts nothing if absent', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = { - search() { - return Promise.resolve({}); - }, - searchForFacetValues() { - return Promise.resolve({}); - }, - }; - - const { ua } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(ua).toBe(undefined); - }); - }); - - describe('widgets', () => { - test('detects empty widgets', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = algoliasearch( - 'appId', - 'apiKey' - ) as unknown as SearchClient; - - const { widgets } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(widgets).toEqual([]); - }); - - test('detects a widget', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = algoliasearch( - 'appId', - 'apiKey' - ) as unknown as SearchClient; - - const RawSearchBox = () => null; - - const SearchBox = connectSearchBox(RawSearchBox); - - render( - - - - ); - - const { widgets } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(widgets).toEqual([ - { - $$type: 'ais.searchBox', - $$widgetType: undefined, - displayName: 'AlgoliaSearchBox', - params: [], - }, - ]); - }); - - test('detects $$widgetType', () => { - const widgetsManager = createWidgetsManager(() => {}); - const searchClient = algoliasearch( - 'appId', - 'apiKey' - ) as unknown as SearchClient; - - const RawSearchBox = () => null; - - const SearchBox = connectSearchBox(RawSearchBox, { - $$widgetType: 'ais.searchBox', - }); - - render( - - - - ); - - const { widgets } = getMetadataPayload( - widgetsManager.getWidgets(), - searchClient - ); - - expect(widgets).toEqual([ - { - $$type: 'ais.searchBox', - $$widgetType: 'ais.searchBox', - displayName: 'AlgoliaSearchBox', - params: [], - }, - ]); - }); - }); -}); - -function FakeProvider({ - children, - widgetsManager, -}: { - children: React.ReactNode; - widgetsManager: any; -}) { - const createFakeState = () => ({ - widgets: {}, - results: {}, - resultsFacetValues: {}, - searching: false, - searchingForFacetValues: false, - isSearchStalled: false, - metadata: [], - error: new Error(), - }); - - return ( - '', - mainTargetedIndex: '', - onInternalStateUpdate: () => {}, - onSearchForFacetValues: () => {}, - onSearchParameters: () => {}, - onSearchStateChange: () => {}, - store: createStore(createFakeState()), - widgetsManager, - }} - > - {children} - - ); -} diff --git a/packages/react-instantsearch-core/src/core/__tests__/translatable.js b/packages/react-instantsearch-core/src/core/__tests__/translatable.js deleted file mode 100644 index f102f16277..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/translatable.js +++ /dev/null @@ -1,43 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import translatable from '../translatable'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('translatable', () => { - it('provides a translate prop to the composed component', () => { - const Dummy = () => null; - const defaultTranslations = { - sup: 'hey', - thing: (n) => `${n} things`, - }; - const Translated = translatable(defaultTranslations)(Dummy); - const { translate } = shallow() - .find(Dummy) - .props(); - expect(translate('sup')).toBe('hey'); - expect(translate('thing', 20)).toBe('20 things'); - }); - - it('uses the translations passed as props before the default', () => { - const Dummy = () => null; - const defaultTranslations = { - sup: 'hey', - thing: (n) => `${n} things`, - fallbackThing: 'hi', - }; - const translations = { - sup: 'hoy', - fallbackThing: undefined, - }; - const Translated = translatable(defaultTranslations)(Dummy); - const { translate } = shallow() - .find(Dummy) - .props(); - expect(translate('sup')).toBe('hoy'); - expect(translate('thing', 20)).toBe('20 things'); - expect(translate('fallbackThing')).toBe(undefined); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/__tests__/utils.js b/packages/react-instantsearch-core/src/core/__tests__/utils.js deleted file mode 100644 index 9415cf0d45..0000000000 --- a/packages/react-instantsearch-core/src/core/__tests__/utils.js +++ /dev/null @@ -1,364 +0,0 @@ -import { Component } from 'react'; - -import * as utils from '../utils'; - -describe('utils', () => { - describe('getDisplayName', () => { - it('gets the right displayName from classes', () => { - class SuperComponent extends Component { - render() { - return null; - } - } - - expect(utils.getDisplayName(SuperComponent)).toBe('SuperComponent'); - }); - - // this works because babel turns arrows functions to named function expressions - it('gets the right displayName from stateless components', () => { - const SuperComponent = () => null; // => var SuperComponent = function SuperComponent() {} - expect(utils.getDisplayName(SuperComponent)).toBe('SuperComponent'); - }); - - it('sets a default displayName when not able to find one', () => { - expect(utils.getDisplayName(() => null)).toBe('UnknownComponent'); - }); - }); - - describe('defer', () => { - it('calling a function asynchronously, should be done as soon as possible.', () => { - let count = 0; - - utils.defer(() => { - count = 1; - }); - - return Promise.resolve().then(() => { - expect(count).toEqual(1); - }); - }); - }); - - describe('remove empty key', () => { - it('empty key should be removed', () => { - const state = { - query: '', - page: 2, - sortBy: 'mostPopular', - range: { - price: { - min: 20, - max: 3000, - }, - }, - refinementList: {}, - indices: { - index1: { - configure: { - hitsPerPage: 3, - refinementList: {}, - }, - }, - index2: { - configure: { - hitsPerPage: 10, - }, - refinementList: { - fruits: ['lemon', 'orange'], - }, - }, - }, - }; - - const newState = utils.removeEmptyKey(state); - - expect(newState).toEqual({ - query: '', - page: 2, - sortBy: 'mostPopular', - range: { - price: { - min: 20, - max: 3000, - }, - }, - indices: { - index1: { - configure: { - hitsPerPage: 3, - }, - }, - index2: { - configure: { - hitsPerPage: 10, - }, - refinementList: { - fruits: ['lemon', 'orange'], - }, - }, - }, - }); - }); - - it('does not do anything on empty root', () => { - expect(utils.removeEmptyKey({})).toEqual({}); - }); - - it('does empty out objects', () => { - expect(utils.removeEmptyKey({ test: {} })).toEqual({}); - expect(utils.removeEmptyKey({ test: { dog: {} } })).toEqual({ - // this one stays, because we have no multipass algorithm - test: {}, - }); - }); - - it('does not empty out arrays', () => { - expect(utils.removeEmptyKey({ test: [] })).toEqual({ test: [] }); - expect(utils.removeEmptyKey({ test: { dog: [] } })).toEqual({ - test: { dog: [] }, - }); - }); - }); - - describe('removeEmptyArraysFromObject', () => { - it('removes empty arrays from objects', () => { - expect( - utils.removeEmptyArraysFromObject({ - disjunctiveFacets: [], - facetFilters: ['categories'], - facets: [], - filters: 'NOT objectID:1', - hierarchicalFacets: [], - optionalFilters: ['brand:Amazon'], - sumOrFiltersScores: true, - tagRefinements: [], - }) - ).toEqual({ - facetFilters: ['categories'], - filters: 'NOT objectID:1', - optionalFilters: ['brand:Amazon'], - sumOrFiltersScores: true, - }); - }); - }); - - describe('addAbsolutePositions', () => { - const allHits = [ - { objectID: '1' }, - { objectID: '2' }, - { objectID: '3' }, - { objectID: '4' }, - { objectID: '5' }, - { objectID: '6' }, - ]; - const hitsPerPage = 2; - it('should add __positions 1 and 2 on page 0', () => { - const hits = allHits.slice(0, 2); - const page = 0; - expect(utils.addAbsolutePositions(hits, hitsPerPage, page)).toEqual([ - { objectID: '1', __position: 1 }, - { objectID: '2', __position: 2 }, - ]); - }); - it('should add __positions 5 and 6 on page 2', () => { - const hits = allHits.slice(4, 6); - const page = 2; - expect(utils.addAbsolutePositions(hits, hitsPerPage, page)).toEqual([ - { objectID: '5', __position: 5 }, - { objectID: '6', __position: 6 }, - ]); - }); - }); - - describe('addQueryID', () => { - const hits = [{ objectID: '1' }, { objectID: '2' }]; - it('should passed __queryID to hits', () => { - expect(utils.addQueryID(hits, 'theQueryID')).toEqual([ - { objectID: '1', __queryID: 'theQueryID' }, - { objectID: '2', __queryID: 'theQueryID' }, - ]); - }); - }); - - describe('getPropertyByPath', () => { - it('returns undefined on non-object root', () => { - expect(utils.getPropertyByPath(false, 'fake')).toBeUndefined(); - expect(utils.getPropertyByPath(undefined, 'fake')).toBeUndefined(); - expect(utils.getPropertyByPath(null, 'fake.nested')).toBeUndefined(); - }); - - it('returns path if exists', () => { - expect(utils.getPropertyByPath({ dog: true }, 'dog')).toBe(true); - expect( - utils.getPropertyByPath( - { i: { like: { properties: false } } }, - 'i.like.properties' - ) - ).toBe(false); - expect( - utils.getPropertyByPath({ true: { nested: 'ok' } }, 'true.nested') - ).toBe('ok'); - }); - - it('accepts a pre-split path as array', () => { - expect(utils.getPropertyByPath({ dog: true }, ['dog'])).toBe(true); - expect( - utils.getPropertyByPath({ i: { like: { properties: false } } }, [ - 'i', - 'like', - 'properties', - ]) - ).toBe(false); - expect( - utils.getPropertyByPath({ true: { nested: 'ok' } }, ['true', 'nested']) - ).toBe('ok'); - }); - - it('does not split a pre-split path as array', () => { - expect(utils.getPropertyByPath({ dog: true }, ['dog'])).toBe(true); - expect( - utils.getPropertyByPath({ i: { like: { properties: false } } }, [ - 'i', - 'like.properties', - ]) - ).toBeUndefined(); - expect( - utils.getPropertyByPath({ true: { nested: 'ok' } }, ['true.nested']) - ).toBeUndefined(); - }); - - it('returns undefined if does not exist', () => { - expect( - utils.getPropertyByPath( - { name: { known: { value: '' } } }, - 'name.unkown' - ) - ).toBeUndefined(); - - expect(utils.getPropertyByPath({ name: false }, 'name.unkown')).toBe( - undefined - ); - }); - - it('returns indexed path if exists', () => { - expect( - utils.getPropertyByPath({ array: ['a', 'b', 'c'] }, 'array.2') - ).toBe('c'); - expect( - utils.getPropertyByPath( - { array: [{ letter: 'a' }, { letter: 'b' }, { letter: 'c' }] }, - 'array.2.letter' - ) - ).toBe('c'); - - expect( - utils.getPropertyByPath({ array: ['a', 'b', 'c'] }, 'array[2]') - ).toBe('c'); - expect( - utils.getPropertyByPath( - { array: [{ letter: 'a' }, { letter: 'b' }, { letter: 'c' }] }, - 'array[2].letter' - ) - ).toBe('c'); - }); - - it('returns undefined if indexed path does not exist', () => { - expect( - utils.getPropertyByPath({ array: ['a', 'b', 'c'] }, 'array.4') - ).toBeUndefined(); - expect( - utils.getPropertyByPath( - { array: [{ letter: 'a' }, { letter: 'b' }, { letter: 'c' }] }, - 'array.5.letter' - ) - ).toBeUndefined(); - - expect( - utils.getPropertyByPath({ array: ['a', 'b', 'c'] }, 'array[4]') - ).toBeUndefined(); - expect( - utils.getPropertyByPath( - { array: [{ letter: 'a' }, { letter: 'b' }, { letter: 'c' }] }, - 'array[5].letter' - ) - ).toBeUndefined(); - }); - }); - - describe('find', () => { - test('returns the first match based on the comparator', () => { - expect( - utils.find([1], () => { - return true; - }) - ).toBe(1); - expect( - utils.find([1, 2], () => { - return true; - }) - ).toBe(1); - - expect( - utils.find([{ nice: false }, { nice: true }], function (el) { - return el.nice; - }) - ).toEqual({ nice: true }); - }); - - test('returns undefined in non-found cases', () => { - expect( - utils.find([], () => { - return false; - }) - ).toBeUndefined(); - expect( - utils.find(undefined, () => { - return false; - }) - ).toBeUndefined(); - - expect(() => { - utils.find([1, 2, 3], undefined); - }).toThrow(); - }); - }); - - describe('getObjectType', () => { - test('returns the type of a string', () => { - expect(utils.getObjectType('string')).toEqual('String'); - }); - - test('returns the type of a number', () => { - expect(utils.getObjectType(2)).toEqual('Number'); - }); - - test('returns the type of a boolean', () => { - expect(utils.getObjectType(true)).toEqual('Boolean'); - expect(utils.getObjectType(false)).toEqual('Boolean'); - }); - - test('returns the type of an object', () => { - expect(utils.getObjectType({})).toEqual('Object'); - }); - - test('returns the type of an array', () => { - expect(utils.getObjectType([])).toEqual('Array'); - }); - - test('returns the type of a date', () => { - expect(utils.getObjectType(new Date())).toEqual('Date'); - }); - - test('returns the type of a function', () => { - expect(utils.getObjectType(() => {})).toEqual('Function'); - }); - - test('returns the type of undefined', () => { - expect(utils.getObjectType(undefined)).toEqual('Undefined'); - }); - - test('returns the type of null', () => { - expect(utils.getObjectType(null)).toEqual('Null'); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/core/context.ts b/packages/react-instantsearch-core/src/core/context.ts deleted file mode 100644 index 6cbfebbe73..0000000000 --- a/packages/react-instantsearch-core/src/core/context.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { createContext } from 'react'; - -import type { Store } from '../core/createStore'; -import type InstantSearch from '../widgets/InstantSearch'; - -export type InstantSearchContext = { - onInternalStateUpdate: InstantSearch['onWidgetsInternalStateUpdate']; - createHrefForState: InstantSearch['createHrefForState']; - onSearchForFacetValues: InstantSearch['onSearchForFacetValues']; - onSearchStateChange: InstantSearch['onSearchStateChange']; - onSearchParameters: InstantSearch['onSearchParameters']; - store: Store; - widgetsManager: any; - mainTargetedIndex: string; -}; - -export const instantSearchContext = createContext({ - onInternalStateUpdate: () => undefined, - createHrefForState: () => '#', - onSearchForFacetValues: () => undefined, - onSearchStateChange: () => undefined, - onSearchParameters: () => undefined, - store: {} as Store, - widgetsManager: {}, - mainTargetedIndex: '', -}); - -export const { - Consumer: InstantSearchConsumer, - Provider: InstantSearchProvider, -} = instantSearchContext; - -export type IndexContext = - | { - targetedIndex: string; - } - | undefined; - -export const { Consumer: IndexConsumer, Provider: IndexProvider } = - createContext(undefined); diff --git a/packages/react-instantsearch-core/src/core/createConnector.tsx b/packages/react-instantsearch-core/src/core/createConnector.tsx deleted file mode 100644 index 6c0ca934bf..0000000000 --- a/packages/react-instantsearch-core/src/core/createConnector.tsx +++ /dev/null @@ -1,403 +0,0 @@ -import React, { Component } from 'react'; -import isEqual from 'react-fast-compare'; - -import { InstantSearchConsumer, IndexConsumer } from './context'; -import { shallowEqual, getDisplayName, removeEmptyKey } from './utils'; - -import type { InstantSearchContext, IndexContext } from './context'; -import type { ElementType } from 'react'; - -export type ConnectorDescription = { - displayName: string; - $$type: string; - /** - * a function to filter the local state - */ - refine?: (...args: any[]) => any; - /** - * function transforming the local state to a SearchParameters - */ - getSearchParameters?: (...args: any[]) => any; - /** - * metadata of the widget (for current refinements) - */ - getMetadata?: (...args: any[]) => any; - /** - * hook after the state has changed - */ - transitionState?: (...args: any[]) => any; - /** - * transform the state into props passed to the wrapped component. - * Receives (props, widgetStates, searchState, metadata) and returns the local state. - */ - getProvidedProps: (...args: any[]) => any; - /** - * Receives props and return the id that will be used to identify the widget - */ - getId?: (...args: any[]) => string; - /** - * hook when the widget will unmount. Receives (props, searchState) and return a cleaned state. - */ - cleanUp?: (...args: any[]) => any; - searchForFacetValues?: (...args: any[]) => any; - shouldComponentUpdate?: (...args: any[]) => boolean; - /** - * PropTypes forwarded to the wrapped component. - */ - propTypes?: Record; // I can't find a definition for a propTypes object - defaultProps?: Record; -}; - -export type AdditionalWidgetProperties = { - $$widgetType?: string; -}; - -type ConnectorProps = { - contextValue: InstantSearchContext; - indexContextValue?: IndexContext; -}; - -export type ConnectedProps = TWidgetProps & ConnectorProps; - -type ConnectorState = { - providedProps: {}; -}; - -/** - * Connectors are the HOC used to transform React components - * into InstantSearch widgets. - * In order to simplify the construction of such connectors - * `createConnector` takes a description and transform it into - * a connector. - * @param {ConnectorDescription} connectorDesc the description of the connector - * @return {Connector} a function that wraps a component into - * an instantsearch connected one. - */ -export function createConnectorWithoutContext( - connectorDesc: ConnectorDescription -) { - if (!connectorDesc.displayName) { - throw new Error( - '`createConnector` requires you to provide a `displayName` property.' - ); - } - - const isWidget = - typeof connectorDesc.getSearchParameters === 'function' || - typeof connectorDesc.getMetadata === 'function' || - typeof connectorDesc.transitionState === 'function'; - - return ( - Composed: ElementType, - additionalWidgetProperties: AdditionalWidgetProperties = {} - ) => { - class Connector extends Component { - static displayName = `${connectorDesc.displayName}(${getDisplayName( - Composed - )})`; - static $$type = connectorDesc.$$type; - static $$widgetType = additionalWidgetProperties.$$widgetType; - static propTypes = connectorDesc.propTypes; - static defaultProps = connectorDesc.defaultProps; - static _connectorDesc = connectorDesc; - - unsubscribe?: () => void; - unregisterWidget?: () => void; - - cleanupTimerRef: ReturnType | null = null; - isUnmounting = false; - - state: ConnectorState = { - providedProps: this.getProvidedProps(this.props), - }; - - constructor(props: ConnectorProps) { - super(props); - - if (connectorDesc.getSearchParameters) { - this.props.contextValue.onSearchParameters( - connectorDesc.getSearchParameters.bind(this), - { - ais: this.props.contextValue, - multiIndexContext: this.props.indexContextValue, - }, - this.props, - connectorDesc.getMetadata && connectorDesc.getMetadata.bind(this), - connectorDesc.displayName - ); - } - } - - componentDidMount() { - if (this.cleanupTimerRef) { - clearTimeout(this.cleanupTimerRef); - this.cleanupTimerRef = null; - } - - this.unsubscribe = this.props.contextValue.store.subscribe(() => { - if (!this.isUnmounting) { - this.setState({ - providedProps: this.getProvidedProps(this.props), - }); - } - }); - - if (isWidget) { - this.unregisterWidget = - this.props.contextValue.widgetsManager.registerWidget(this); - } - } - - shouldComponentUpdate(nextProps: any, nextState: any) { - if (typeof connectorDesc.shouldComponentUpdate === 'function') { - return connectorDesc.shouldComponentUpdate.call( - this, - this.props, - nextProps, - this.state, - nextState - ); - } - - const propsEqual = shallowEqual(this.props, nextProps); - - if ( - this.state.providedProps === null || - nextState.providedProps === null - ) { - if (this.state.providedProps === nextState.providedProps) { - return !propsEqual; - } - return true; - } - - return ( - !propsEqual || - !shallowEqual(this.state.providedProps, nextState.providedProps) - ); - } - - componentDidUpdate(prevProps: any) { - if (!isEqual(prevProps, this.props)) { - this.setState({ - providedProps: this.getProvidedProps(this.props), - }); - - if (isWidget) { - this.props.contextValue.widgetsManager.update(); - - if (typeof connectorDesc.transitionState === 'function') { - this.props.contextValue.onSearchStateChange( - connectorDesc.transitionState.call( - this, - this.props, - this.props.contextValue.store.getState().widgets, - this.props.contextValue.store.getState().widgets - ) - ); - } - } - } - } - - componentWillUnmount() { - this.cleanupTimerRef = setTimeout(() => { - this.isUnmounting = true; - - if (this.unsubscribe) { - this.unsubscribe(); - } - - if (this.unregisterWidget) { - this.unregisterWidget(); - - if (typeof connectorDesc.cleanUp === 'function') { - const nextState = connectorDesc.cleanUp.call( - this, - this.props, - this.props.contextValue.store.getState().widgets - ); - - this.props.contextValue.store.setState({ - ...this.props.contextValue.store.getState(), - widgets: nextState, - }); - - this.props.contextValue.onSearchStateChange( - removeEmptyKey(nextState) - ); - } - } - }); - } - - getProvidedProps(props: any) { - const { - widgets, - results, - resultsFacetValues, - searching, - searchingForFacetValues, - isSearchStalled, - metadata, - error, - } = this.props.contextValue.store.getState(); - - const searchResults = { - results, - searching, - searchingForFacetValues, - isSearchStalled, - error, - }; - - return connectorDesc.getProvidedProps.call( - this, - props, - widgets, - searchResults, - metadata, - // @MAJOR: move this attribute on the `searchResults` it doesn't - // makes sense to have it into a separate argument. The search - // flags are on the object why not the results? - resultsFacetValues - ); - } - - getSearchParameters(searchParameters: any) { - if (typeof connectorDesc.getSearchParameters === 'function') { - return connectorDesc.getSearchParameters.call( - this, - searchParameters, - this.props, - this.props.contextValue.store.getState().widgets - ); - } - - return null; - } - - getMetadata(nextWidgetsState: any) { - if (typeof connectorDesc.getMetadata === 'function') { - return connectorDesc.getMetadata.call( - this, - this.props, - nextWidgetsState - ); - } - - return {}; - } - - transitionState(prevWidgetsState: any, nextWidgetsState: any) { - if (typeof connectorDesc.transitionState === 'function') { - return connectorDesc.transitionState.call( - this, - this.props, - prevWidgetsState, - nextWidgetsState - ); - } - - return nextWidgetsState; - } - - refine = (...args: any[]) => { - this.props.contextValue.onInternalStateUpdate( - // refine will always be defined here because the prop is only given conditionally - connectorDesc.refine!.call( - this, - this.props, - this.props.contextValue.store.getState().widgets, - ...args - ) - ); - }; - - createURL = (...args: any[]) => - this.props.contextValue.createHrefForState( - // refine will always be defined here because the prop is only given conditionally - connectorDesc.refine!.call( - this, - this.props, - this.props.contextValue.store.getState().widgets, - ...args - ) - ); - - searchForFacetValues = (...args: any[]) => { - this.props.contextValue.onSearchForFacetValues( - // searchForFacetValues will always be defined here because the prop is only given conditionally - connectorDesc.searchForFacetValues!.call( - this, - this.props, - this.props.contextValue.store.getState().widgets, - ...args - ) - ); - }; - - render() { - const { contextValue, ...props } = this.props; - const { providedProps } = this.state; - - if (providedProps === null) { - return null; - } - - const refineProps = - typeof connectorDesc.refine === 'function' - ? { refine: this.refine, createURL: this.createURL } - : {}; - - const searchForFacetValuesProps = - typeof connectorDesc.searchForFacetValues === 'function' - ? { searchForItems: this.searchForFacetValues } - : {}; - - return ( - - ); - } - } - - return Connector; - }; -} - -const createConnectorWithContext = - (connectorDesc: ConnectorDescription) => - ( - Composed: ElementType, - additionalWidgetProperties?: AdditionalWidgetProperties - ) => { - const Connector = createConnectorWithoutContext(connectorDesc)( - Composed, - additionalWidgetProperties - ); - - const ConnectorWrapper: React.FC = (props) => ( - - {(contextValue) => ( - - {(indexContextValue) => ( - - )} - - )} - - ); - - return ConnectorWrapper; - }; - -export default createConnectorWithContext; diff --git a/packages/react-instantsearch-core/src/core/createInstantSearchManager.d.ts b/packages/react-instantsearch-core/src/core/createInstantSearchManager.d.ts deleted file mode 100644 index 6f9b35a2f8..0000000000 --- a/packages/react-instantsearch-core/src/core/createInstantSearchManager.d.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default function createInstantSearchManager(props: { - indexName: string; - initialState: object; - searchClient: object; - resultsState?: object; - stalledSearchDelay?: number; -}): any; diff --git a/packages/react-instantsearch-core/src/core/createInstantSearchManager.js b/packages/react-instantsearch-core/src/core/createInstantSearchManager.js deleted file mode 100644 index c402519023..0000000000 --- a/packages/react-instantsearch-core/src/core/createInstantSearchManager.js +++ /dev/null @@ -1,644 +0,0 @@ -import algoliasearchHelper from 'algoliasearch-helper'; -import { version as ReactVersion } from 'react'; - -import createStore from './createStore'; -import createWidgetsManager from './createWidgetsManager'; -import { HIGHLIGHT_TAGS } from './highlight'; -import { hasMultipleIndices } from './indexUtils'; -import version from './version'; - -function addAlgoliaAgents(searchClient) { - if (typeof searchClient.addAlgoliaAgent === 'function') { - searchClient.addAlgoliaAgent(`react (${ReactVersion})`); - searchClient.addAlgoliaAgent(`react-instantsearch (${version})`); - } -} - -const isMultiIndexContext = (widget) => - hasMultipleIndices({ - ais: widget.props.contextValue, - multiIndexContext: widget.props.indexContextValue, - }); -const isTargetedIndexEqualIndex = (widget, indexId) => - widget.props.indexContextValue.targetedIndex === indexId; - -// Relying on the `indexId` is a bit brittle to detect the `Index` widget. -// Since it's a class we could rely on `instanceof` or similar. We never -// had an issue though. Works for now. -const isIndexWidget = (widget) => Boolean(widget.props.indexId); -const isIndexWidgetEqualIndex = (widget, indexId) => - widget.props.indexId === indexId; - -const sortIndexWidgetsFirst = (firstWidget, secondWidget) => { - const isFirstWidgetIndex = isIndexWidget(firstWidget); - const isSecondWidgetIndex = isIndexWidget(secondWidget); - - if (isFirstWidgetIndex && !isSecondWidgetIndex) { - return -1; - } - if (!isFirstWidgetIndex && isSecondWidgetIndex) { - return 1; - } - return 0; -}; - -// This function is copied from the algoliasearch v4 API Client. If modified, -// consider updating it also in `serializeQueryParameters` from `@algolia/transporter`. -function serializeQueryParameters(parameters) { - const isObjectOrArray = (value) => - Object.prototype.toString.call(value) === '[object Object]' || - Object.prototype.toString.call(value) === '[object Array]'; - - const encode = (format, ...args) => { - let i = 0; - return format.replace(/%s/g, () => encodeURIComponent(args[i++])); - }; - - return Object.keys(parameters) - .map((key) => - encode( - '%s=%s', - key, - isObjectOrArray(parameters[key]) - ? JSON.stringify(parameters[key]) - : parameters[key] - ) - ) - .join('&'); -} - -/** - * Creates a new instance of the InstantSearchManager which controls the widgets and - * trigger the search when the widgets are updated. - * @param {string} indexName - the main index name - * @param {object} initialState - initial widget state - * @param {object} SearchParameters - optional additional parameters to send to the algolia API - * @param {number} stalledSearchDelay - time (in ms) after the search is stalled - * @return {InstantSearchManager} a new instance of InstantSearchManager - */ -export default function createInstantSearchManager({ - indexName, - initialState = {}, - searchClient, - resultsState, - stalledSearchDelay, -}) { - const helper = algoliasearchHelper(searchClient, indexName, { - ...HIGHLIGHT_TAGS, - }); - - addAlgoliaAgents(searchClient); - - helper - .on('search', handleNewSearch) - .on('result', handleSearchSuccess({ indexId: indexName })) - .on('error', handleSearchError); - - let skip = false; - let stalledSearchTimer = null; - let initialSearchParameters = helper.state; - let searchCounter; - - const widgetsManager = createWidgetsManager(onWidgetsUpdate); - - hydrateSearchClient(searchClient, resultsState); - - const store = createStore({ - widgets: initialState, - metadata: hydrateMetadata(resultsState), - results: hydrateResultsState(resultsState), - error: null, - searching: false, - isSearchStalled: true, - searchingForFacetValues: false, - }); - - function skipSearch() { - skip = true; - } - - function updateClient(client) { - addAlgoliaAgents(client); - helper.setClient(client); - search(); - } - - function clearCache() { - helper.clearCache(); - search(); - } - - function getMetadata(state) { - return widgetsManager - .getWidgets() - .filter((widget) => Boolean(widget.getMetadata)) - .map((widget) => widget.getMetadata(state)); - } - - function getSearchParameters() { - const sharedParameters = widgetsManager - .getWidgets() - .filter((widget) => Boolean(widget.getSearchParameters)) - .filter( - (widget) => !isMultiIndexContext(widget) && !isIndexWidget(widget) - ) - .reduce( - (res, widget) => widget.getSearchParameters(res), - initialSearchParameters - ); - - const mainParameters = widgetsManager - .getWidgets() - .filter((widget) => Boolean(widget.getSearchParameters)) - .filter((widget) => { - const targetedIndexEqualMainIndex = - isMultiIndexContext(widget) && - isTargetedIndexEqualIndex(widget, indexName); - - const subIndexEqualMainIndex = - isIndexWidget(widget) && isIndexWidgetEqualIndex(widget, indexName); - - return targetedIndexEqualMainIndex || subIndexEqualMainIndex; - }) - // We have to sort the `Index` widgets first so the `index` parameter - // is correctly set in the `reduce` function for the following widgets - .sort(sortIndexWidgetsFirst) - .reduce( - (res, widget) => widget.getSearchParameters(res), - sharedParameters - ); - - const derivedIndices = widgetsManager - .getWidgets() - .filter((widget) => Boolean(widget.getSearchParameters)) - .filter((widget) => { - const targetedIndexNotEqualMainIndex = - isMultiIndexContext(widget) && - !isTargetedIndexEqualIndex(widget, indexName); - - const subIndexNotEqualMainIndex = - isIndexWidget(widget) && !isIndexWidgetEqualIndex(widget, indexName); - - return targetedIndexNotEqualMainIndex || subIndexNotEqualMainIndex; - }) - // We have to sort the `Index` widgets first so the `index` parameter - // is correctly set in the `reduce` function for the following widgets - .sort(sortIndexWidgetsFirst) - .reduce((indices, widget) => { - const indexId = isMultiIndexContext(widget) - ? widget.props.indexContextValue.targetedIndex - : widget.props.indexId; - - const widgets = indices[indexId] || []; - - return { - ...indices, - [indexId]: widgets.concat(widget), - }; - }, {}); - - const derivedParameters = Object.keys(derivedIndices).map((indexId) => ({ - parameters: derivedIndices[indexId].reduce( - (res, widget) => widget.getSearchParameters(res), - sharedParameters - ), - indexId, - })); - - return { - mainParameters, - derivedParameters, - }; - } - - function search() { - if (!skip) { - const { mainParameters, derivedParameters } = getSearchParameters( - helper.state - ); - - searchCounter = derivedParameters.length + 1; - - // We have to call `slice` because the method `detach` on the derived - // helpers mutates the value `derivedHelpers`. The `forEach` loop does - // not iterate on each value and we're not able to correctly clear the - // previous derived helpers (memory leak + useless requests). - helper.derivedHelpers.slice().forEach((derivedHelper) => { - // Since we detach the derived helpers on **every** new search they - // won't receive intermediate results in case of a stalled search. - // Only the last result is dispatched by the derived helper because - // they are not detached yet: - // - // - a -> main helper receives results - // - ap -> main helper receives results - // - app -> main helper + derived helpers receive results - // - // The quick fix is to avoid to detach them on search but only once they - // received the results. But it means that in case of a stalled search - // all the derived helpers not detached yet register a new search inside - // the helper. The number grows fast in case of a bad network and it's - // not deterministic. - derivedHelper.detach(); - }); - - derivedParameters.forEach(({ indexId, parameters }) => { - const derivedHelper = helper.derive(() => parameters); - - derivedHelper - .on('result', handleSearchSuccess({ indexId })) - .on('error', handleSearchError); - }); - - helper.setState(mainParameters); - - helper.search(); - } - } - - function handleSearchSuccess({ indexId }) { - return (event) => { - searchCounter--; - - const state = store.getState(); - const isDerivedHelpersEmpty = !helper.derivedHelpers.length; - - let results = state.results ? state.results : {}; - - // Switching from mono index to multi index and vice versa must reset the - // results to an empty object, otherwise we keep reference of stalled and - // unused results. - results = !isDerivedHelpersEmpty && results.getFacetByName ? {} : results; - - if (!isDerivedHelpersEmpty) { - results = { ...results, [indexId]: event.results }; - } else { - results = event.results; - } - - const currentState = store.getState(); - let nextIsSearchStalled = currentState.isSearchStalled; - if (!helper.hasPendingRequests()) { - clearTimeout(stalledSearchTimer); - stalledSearchTimer = null; - nextIsSearchStalled = false; - } - - const { resultsFacetValues, ...partialState } = currentState; - - store.setState({ - ...partialState, - results, - isSearchStalled: nextIsSearchStalled, - searching: searchCounter > 0, - error: null, - }); - }; - } - - function handleSearchError({ error }) { - const currentState = store.getState(); - - let nextIsSearchStalled = currentState.isSearchStalled; - if (!helper.hasPendingRequests()) { - clearTimeout(stalledSearchTimer); - nextIsSearchStalled = false; - } - - const { resultsFacetValues, ...partialState } = currentState; - - store.setState({ - ...partialState, - isSearchStalled: nextIsSearchStalled, - error, - searching: false, - }); - } - - function handleNewSearch() { - if (!stalledSearchTimer) { - stalledSearchTimer = setTimeout(() => { - const { resultsFacetValues, ...partialState } = store.getState(); - - store.setState({ - ...partialState, - isSearchStalled: true, - }); - }, stalledSearchDelay); - } - } - - function hydrateSearchClient(client, results) { - if (!results) { - return; - } - - // Disable cache hydration on: - // - Algoliasearch API Client < v4 with cache disabled - // - Third party clients (detected by the `addAlgoliaAgent` function missing) - - if ( - (!client.transporter || client._cacheHydrated) && - (!client._useCache || typeof client.addAlgoliaAgent !== 'function') - ) { - return; - } - - // Algoliasearch API Client >= v4 - // To hydrate the client we need to populate the cache with the data from - // the server (done in `hydrateSearchClientWithMultiIndexRequest` or - // `hydrateSearchClientWithSingleIndexRequest`). But since there is no way - // for us to compute the key the same way as `algoliasearch-client` we need - // to populate it on a custom key and override the `search` method to - // search on it first. - if (client.transporter && !client._cacheHydrated) { - client._cacheHydrated = true; - - const baseMethod = client.search; - client.search = (requests, ...methodArgs) => { - const requestsWithSerializedParams = requests.map((request) => ({ - ...request, - params: serializeQueryParameters(request.params), - })); - - return client.transporter.responsesCache.get( - { - method: 'search', - args: [requestsWithSerializedParams, ...methodArgs], - }, - () => { - return baseMethod(requests, ...methodArgs); - } - ); - }; - } - - if (Array.isArray(results.results)) { - hydrateSearchClientWithMultiIndexRequest(client, results.results); - return; - } - - hydrateSearchClientWithSingleIndexRequest(client, results); - } - - function hydrateSearchClientWithMultiIndexRequest(client, results) { - // Algoliasearch API Client >= v4 - // Populate the cache with the data from the server - if (client.transporter) { - client.transporter.responsesCache.set( - { - method: 'search', - args: [ - results.reduce( - (acc, result) => - acc.concat( - result.rawResults.map((request) => ({ - indexName: request.index, - params: request.params, - })) - ), - [] - ), - ], - }, - { - results: results.reduce( - (acc, result) => acc.concat(result.rawResults), - [] - ), - } - ); - return; - } - - // Algoliasearch API Client < v4 - // Prior to client v4 we didn't have a proper API to hydrate the client - // cache from the outside. The following code populates the cache with - // a single-index result. You can find more information about the - // computation of the key inside the client (see link below). - // https://github.com/algolia/algoliasearch-client-javascript/blob/c27e89ff92b2a854ae6f40dc524bffe0f0cbc169/src/AlgoliaSearchCore.js#L232-L240 - const key = `/1/indexes/*/queries_body_${JSON.stringify({ - requests: results.reduce( - (acc, result) => - acc.concat( - result.rawResults.map((request) => ({ - indexName: request.index, - params: request.params, - })) - ), - [] - ), - })}`; - - client.cache = { - ...client.cache, - [key]: JSON.stringify({ - results: results.reduce( - (acc, result) => acc.concat(result.rawResults), - [] - ), - }), - }; - } - - function hydrateSearchClientWithSingleIndexRequest(client, results) { - // Algoliasearch API Client >= v4 - // Populate the cache with the data from the server - if (client.transporter) { - client.transporter.responsesCache.set( - { - method: 'search', - args: [ - results.rawResults.map((request) => ({ - indexName: request.index, - params: request.params, - })), - ], - }, - { - results: results.rawResults, - } - ); - return; - } - // Algoliasearch API Client < v4 - // Prior to client v4 we didn't have a proper API to hydrate the client - // cache from the outside. The following code populates the cache with - // a single-index result. You can find more information about the - // computation of the key inside the client (see link below). - // https://github.com/algolia/algoliasearch-client-javascript/blob/c27e89ff92b2a854ae6f40dc524bffe0f0cbc169/src/AlgoliaSearchCore.js#L232-L240 - const key = `/1/indexes/*/queries_body_${JSON.stringify({ - requests: results.rawResults.map((request) => ({ - indexName: request.index, - params: request.params, - })), - })}`; - - client.cache = { - ...client.cache, - [key]: JSON.stringify({ - results: results.rawResults, - }), - }; - } - - function hydrateResultsState(results) { - if (!results) { - return null; - } - - if (Array.isArray(results.results)) { - return results.results.reduce( - (acc, result) => ({ - ...acc, - [result._internalIndexId]: new algoliasearchHelper.SearchResults( - new algoliasearchHelper.SearchParameters(result.state), - result.rawResults - ), - }), - {} - ); - } - - return new algoliasearchHelper.SearchResults( - new algoliasearchHelper.SearchParameters(results.state), - results.rawResults - ); - } - - // Called whenever a widget has been rendered with new props. - function onWidgetsUpdate() { - const metadata = getMetadata(store.getState().widgets); - - store.setState({ - ...store.getState(), - metadata, - searching: true, - }); - - // Since the `getSearchParameters` method of widgets also depends on props, - // the result search parameters might have changed. - search(); - } - - function transitionState(nextSearchState) { - const searchState = store.getState().widgets; - - return widgetsManager - .getWidgets() - .filter((widget) => Boolean(widget.transitionState)) - .reduce( - (res, widget) => widget.transitionState(searchState, res), - nextSearchState - ); - } - - function onExternalStateUpdate(nextSearchState) { - const metadata = getMetadata(nextSearchState); - - store.setState({ - ...store.getState(), - widgets: nextSearchState, - metadata, - searching: true, - }); - - search(); - } - - function onSearchForFacetValues({ facetName, query, maxFacetHits = 10 }) { - // The values 1, 100 are the min / max values that the engine accepts. - // see: https://www.algolia.com/doc/api-reference/api-parameters/maxFacetHits - const maxFacetHitsWithinRange = Math.max(1, Math.min(maxFacetHits, 100)); - - store.setState({ - ...store.getState(), - searchingForFacetValues: true, - }); - - helper - .searchForFacetValues(facetName, query, maxFacetHitsWithinRange) - .then( - (content) => { - store.setState({ - ...store.getState(), - error: null, - searchingForFacetValues: false, - resultsFacetValues: { - ...store.getState().resultsFacetValues, - [facetName]: content.facetHits, - query, - }, - }); - }, - (error) => { - store.setState({ - ...store.getState(), - searchingForFacetValues: false, - error, - }); - } - ) - .catch((error) => { - // Since setState is synchronous, any error that occurs in the render of a - // component will be swallowed by this promise. - // This is a trick to make the error show up correctly in the console. - // See http://stackoverflow.com/a/30741722/969302 - setTimeout(() => { - throw error; - }); - }); - } - - function updateIndex(newIndex) { - initialSearchParameters = initialSearchParameters.setIndex(newIndex); - // No need to trigger a new search here as the widgets will also update and trigger it if needed. - } - - function getWidgetsIds() { - return store - .getState() - .metadata.reduce( - (res, meta) => - typeof meta.id !== 'undefined' ? res.concat(meta.id) : res, - [] - ); - } - - return { - store, - widgetsManager, - getWidgetsIds, - getSearchParameters, - onSearchForFacetValues, - onExternalStateUpdate, - transitionState, - updateClient, - updateIndex, - clearCache, - skipSearch, - }; -} - -function hydrateMetadata(resultsState) { - if (!resultsState) { - return []; - } - - // add a value noop, which gets replaced once the widgets are mounted - return resultsState.metadata.map((datum) => ({ - value: () => ({}), - ...datum, - items: - datum.items && - datum.items.map((item) => ({ - value: () => ({}), - ...item, - items: - item.items && - item.items.map((nestedItem) => ({ - value: () => ({}), - ...nestedItem, - })), - })), - })); -} diff --git a/packages/react-instantsearch-core/src/core/createStore.ts b/packages/react-instantsearch-core/src/core/createStore.ts deleted file mode 100644 index 11bcf1a37c..0000000000 --- a/packages/react-instantsearch-core/src/core/createStore.ts +++ /dev/null @@ -1,35 +0,0 @@ -type SearchState = any; -type ResultsState = any; -type ResultsFacetsValues = any; -type Listener = () => void; -type State = { - widgets: SearchState; - metadata: any[]; - results: ResultsState | null; - resultsFacetValues: ResultsFacetsValues | null; - error: Error | null; - searching: boolean; - isSearchStalled: boolean; - searchingForFacetValues: boolean; -}; -export default function createStore(initialState: State) { - let state = initialState; - const listeners: Listener[] = []; - return { - getState() { - return state; - }, - setState(nextState: State) { - state = nextState; - listeners.forEach((listener) => listener()); - }, - subscribe(listener: Listener) { - listeners.push(listener); - return function unsubscribe() { - listeners.splice(listeners.indexOf(listener), 1); - }; - }, - }; -} - -export type Store = ReturnType; diff --git a/packages/react-instantsearch-core/src/core/createWidgetsManager.ts b/packages/react-instantsearch-core/src/core/createWidgetsManager.ts deleted file mode 100644 index be0f3634ab..0000000000 --- a/packages/react-instantsearch-core/src/core/createWidgetsManager.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { defer } from './utils'; - -import type { ConnectorDescription } from './createConnector'; -import type { Component } from 'react'; - -export type Widget = Component & { - constructor: { - displayName?: string; - $$type?: string; - $$widgetType?: string; - _connectorDesc?: ConnectorDescription; - }; -}; - -export type WidgetsManager = ReturnType; - -export default function createWidgetsManager(onWidgetsUpdate: () => void) { - const widgets: Widget[] = []; - // Is an update scheduled? - let scheduled = false; - - // The state manager's updates need to be batched since more than one - // component can register or unregister widgets during the same tick. - function scheduleUpdate() { - if (scheduled) { - return; - } - scheduled = true; - defer(() => { - scheduled = false; - onWidgetsUpdate(); - }); - } - - return { - registerWidget(widget: Widget) { - widgets.push(widget); - scheduleUpdate(); - return function unregisterWidget() { - widgets.splice(widgets.indexOf(widget), 1); - scheduleUpdate(); - }; - }, - update: scheduleUpdate, - getWidgets() { - return widgets; - }, - }; -} diff --git a/packages/react-instantsearch-core/src/core/highlight.js b/packages/react-instantsearch-core/src/core/highlight.js deleted file mode 100644 index d76adb7051..0000000000 --- a/packages/react-instantsearch-core/src/core/highlight.js +++ /dev/null @@ -1,93 +0,0 @@ -import { getPropertyByPath } from './utils'; - -export const HIGHLIGHT_TAGS = { - highlightPreTag: ``, - highlightPostTag: ``, -}; - -/** - * Parses an highlighted attribute into an array of objects with the string value, and - * a boolean that indicated if this part is highlighted. - * - * @param {string} preTag - string used to identify the start of an highlighted value - * @param {string} postTag - string used to identify the end of an highlighted value - * @param {string} highlightedValue - highlighted attribute as returned by Algolia highlight feature - * @return {object[]} - An array of {value: string, isHighlighted: boolean}. - */ -function parseHighlightedAttribute({ preTag, postTag, highlightedValue = '' }) { - const splitByPreTag = highlightedValue.split(preTag); - const firstValue = splitByPreTag.shift(); - const elements = - firstValue === '' ? [] : [{ value: firstValue, isHighlighted: false }]; - - if (postTag === preTag) { - let isHighlighted = true; - splitByPreTag.forEach((split) => { - elements.push({ value: split, isHighlighted }); - isHighlighted = !isHighlighted; - }); - } else { - splitByPreTag.forEach((split) => { - const splitByPostTag = split.split(postTag); - - elements.push({ - value: splitByPostTag[0], - isHighlighted: true, - }); - - if (splitByPostTag[1] !== '') { - elements.push({ - value: splitByPostTag[1], - isHighlighted: false, - }); - } - }); - } - - return elements; -} - -/** - * Find an highlighted attribute given an `attribute` and an `highlightProperty`, parses it, - * and provided an array of objects with the string value and a boolean if this - * value is highlighted. - * - * In order to use this feature, highlight must be activated in the configuration of - * the index. The `preTag` and `postTag` attributes are respectively highlightPreTag and - * highlightPostTag in Algolia configuration. - * - * @param {string} preTag - string used to identify the start of an highlighted value - * @param {string} postTag - string used to identify the end of an highlighted value - * @param {string} highlightProperty - the property that contains the highlight structure in the results - * @param {string} attribute - the highlighted attribute to look for - * @param {object} hit - the actual hit returned by Algolia. - * @return {object[]} - An array of {value: string, isHighlighted: boolean}. - */ -export function parseAlgoliaHit({ - preTag = '', - postTag = '', - highlightProperty, - attribute, - hit, -}) { - if (!hit) throw new Error('`hit`, the matching record, must be provided'); - - const highlightObject = - getPropertyByPath(hit[highlightProperty], attribute) || {}; - - if (Array.isArray(highlightObject)) { - return highlightObject.map((item) => - parseHighlightedAttribute({ - preTag, - postTag, - highlightedValue: item.value, - }) - ); - } - - return parseHighlightedAttribute({ - preTag, - postTag, - highlightedValue: highlightObject.value, - }); -} diff --git a/packages/react-instantsearch-core/src/core/indexUtils.js b/packages/react-instantsearch-core/src/core/indexUtils.js deleted file mode 100644 index b7a467800d..0000000000 --- a/packages/react-instantsearch-core/src/core/indexUtils.js +++ /dev/null @@ -1,327 +0,0 @@ -import { omit } from './utils'; - -export function getIndexId(context) { - return hasMultipleIndices(context) - ? context.multiIndexContext.targetedIndex - : context.ais.mainTargetedIndex; -} - -// eslint-disable-next-line valid-jsdoc -/** - * @returns {import('algoliasearch-helper').SearchResults} results - */ -export function getResults(searchResults, context) { - if (searchResults.results) { - if (searchResults.results.hits) { - return searchResults.results; - } - - const indexId = getIndexId(context); - if (searchResults.results[indexId]) { - return searchResults.results[indexId]; - } - } - - return null; -} - -export function hasMultipleIndices(context) { - return context && context.multiIndexContext; -} - -export function refineValue( - searchState, - nextRefinement, - context, - resetPage, - namespace -) { - if (hasMultipleIndices(context)) { - const indexId = getIndexId(context); - return namespace - ? refineMultiIndexWithNamespace( - searchState, - nextRefinement, - indexId, - resetPage, - namespace - ) - : refineMultiIndex(searchState, nextRefinement, indexId, resetPage); - } else { - // When we have a multi index page with shared widgets we should also - // reset their page to 1 if the resetPage is provided. Otherwise the - // indices will always be reset - // see: https://github.com/algolia/react-instantsearch/issues/310 - // see: https://github.com/algolia/react-instantsearch/issues/637 - if (searchState.indices && resetPage) { - Object.keys(searchState.indices).forEach((targetedIndex) => { - searchState = refineValue( - searchState, - { page: 1 }, - { multiIndexContext: { targetedIndex } }, - true, - namespace - ); - }); - } - return namespace - ? refineSingleIndexWithNamespace( - searchState, - nextRefinement, - resetPage, - namespace - ) - : refineSingleIndex(searchState, nextRefinement, resetPage); - } -} - -function refineMultiIndex(searchState, nextRefinement, indexId, resetPage) { - const page = resetPage ? { page: 1 } : undefined; - const state = - searchState.indices && searchState.indices[indexId] - ? { - ...searchState.indices, - [indexId]: { - ...searchState.indices[indexId], - ...nextRefinement, - ...page, - }, - } - : { - ...searchState.indices, - [indexId]: { - ...nextRefinement, - ...page, - }, - }; - - return { - ...searchState, - indices: state, - }; -} - -function refineSingleIndex(searchState, nextRefinement, resetPage) { - const page = resetPage ? { page: 1 } : undefined; - return { ...searchState, ...nextRefinement, ...page }; -} - -function refineMultiIndexWithNamespace( - searchState, - nextRefinement, - indexId, - resetPage, - namespace -) { - const page = resetPage ? { page: 1 } : undefined; - const state = - searchState.indices && searchState.indices[indexId] - ? { - ...searchState.indices, - [indexId]: { - ...searchState.indices[indexId], - [namespace]: { - ...searchState.indices[indexId][namespace], - ...nextRefinement, - }, - page: 1, - }, - } - : { - ...searchState.indices, - [indexId]: { - [namespace]: nextRefinement, - ...page, - }, - }; - - return { - ...searchState, - indices: state, - }; -} - -function refineSingleIndexWithNamespace( - searchState, - nextRefinement, - resetPage, - namespace -) { - const page = resetPage ? { page: 1 } : undefined; - return { - ...searchState, - [namespace]: { ...searchState[namespace], ...nextRefinement }, - ...page, - }; -} - -function getNamespaceAndAttributeName(id) { - const parts = id.match(/^([^.]*)\.(.*)/); - const namespace = parts && parts[1]; - const attributeName = parts && parts[2]; - - return { namespace, attributeName }; -} - -function hasRefinements({ - multiIndex, - indexId, - namespace, - attributeName, - id, - searchState, -}) { - if (multiIndex && namespace) { - return ( - searchState.indices && - searchState.indices[indexId] && - searchState.indices[indexId][namespace] && - Object.hasOwnProperty.call( - searchState.indices[indexId][namespace], - attributeName - ) - ); - } - - if (multiIndex) { - return ( - searchState.indices && - searchState.indices[indexId] && - Object.hasOwnProperty.call(searchState.indices[indexId], id) - ); - } - - if (namespace) { - return ( - searchState[namespace] && - Object.hasOwnProperty.call(searchState[namespace], attributeName) - ); - } - - return Object.hasOwnProperty.call(searchState, id); -} - -function getRefinements({ - multiIndex, - indexId, - namespace, - attributeName, - id, - searchState, -}) { - if (multiIndex && namespace) { - return searchState.indices[indexId][namespace][attributeName]; - } - if (multiIndex) { - return searchState.indices[indexId][id]; - } - if (namespace) { - return searchState[namespace][attributeName]; - } - - return searchState[id]; -} - -export function getCurrentRefinementValue( - props, - searchState, - context, - id, - defaultValue -) { - const indexId = getIndexId(context); - const { namespace, attributeName } = getNamespaceAndAttributeName(id); - const multiIndex = hasMultipleIndices(context); - const args = { - multiIndex, - indexId, - namespace, - attributeName, - id, - searchState, - }; - const hasRefinementsValue = hasRefinements(args); - - if (hasRefinementsValue) { - return getRefinements(args); - } - - if (props.defaultRefinement) { - return props.defaultRefinement; - } - - return defaultValue; -} - -export function cleanUpValue(searchState, context, id) { - const indexId = getIndexId(context); - const { namespace, attributeName } = getNamespaceAndAttributeName(id); - - if (hasMultipleIndices(context) && Boolean(searchState.indices)) { - return cleanUpValueWithMultiIndex({ - attribute: attributeName, - searchState, - indexId, - id, - namespace, - }); - } - - return cleanUpValueWithSingleIndex({ - attribute: attributeName, - searchState, - id, - namespace, - }); -} - -function cleanUpValueWithSingleIndex({ - searchState, - id, - namespace, - attribute, -}) { - if (namespace) { - return { - ...searchState, - [namespace]: omit(searchState[namespace], [attribute]), - }; - } - - return omit(searchState, [id]); -} - -function cleanUpValueWithMultiIndex({ - searchState, - indexId, - id, - namespace, - attribute, -}) { - const indexSearchState = searchState.indices[indexId]; - - if (namespace && indexSearchState) { - return { - ...searchState, - indices: { - ...searchState.indices, - [indexId]: { - ...indexSearchState, - [namespace]: omit(indexSearchState[namespace], [attribute]), - }, - }, - }; - } - - if (indexSearchState) { - return { - ...searchState, - indices: { - ...searchState.indices, - [indexId]: omit(indexSearchState, [id]), - }, - }; - } - - return searchState; -} diff --git a/packages/react-instantsearch-core/src/core/metadata.ts b/packages/react-instantsearch-core/src/core/metadata.ts deleted file mode 100644 index 7b5b0a9d26..0000000000 --- a/packages/react-instantsearch-core/src/core/metadata.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { SearchClient } from '../widgets/InstantSearch'; -import type { Widget } from './createWidgetsManager'; - -export function isMetadataEnabled() { - return ( - typeof window === 'object' && - typeof window.navigator === 'object' && - typeof window.navigator.userAgent === 'string' && - window.navigator.userAgent.includes('Algolia Crawler') && - typeof window.document === 'object' - ); -} - -export function getMetadataPayload( - widgets: Widget[], - searchClient: SearchClient -) { - const internalProps = ['contextValue', 'indexContextValue']; - - const widgetsPayload = widgets.map(({ props, constructor }) => { - const { defaultProps = {}, displayName = constructor.displayName } = - constructor._connectorDesc || {}; - - return { - displayName, - $$type: constructor.$$type, - $$widgetType: constructor.$$widgetType, - params: Object.keys(props).filter( - (prop) => - !internalProps.includes(prop) && - defaultProps[prop] !== (props as any)[prop] && - (props as any)[prop] !== undefined - ), - }; - }); - - const client = searchClient as Record; - const ua = - client.transporter && client.transporter.userAgent - ? client.transporter.userAgent.value - : client._ua; - - return { - ua, - widgets: widgetsPayload, - }; -} - -export function injectMetadata(widgets: Widget[], searchClient: SearchClient) { - const payloadContainer = document.createElement('meta'); - const refNode = document.querySelector('head')!; - payloadContainer.name = 'algolia:metadata'; - - const payload = getMetadataPayload(widgets, searchClient); - - payloadContainer.content = JSON.stringify(payload); - refNode.appendChild(payloadContainer); -} diff --git a/packages/react-instantsearch-core/src/core/translatable.js b/packages/react-instantsearch-core/src/core/translatable.js deleted file mode 100644 index 13d483c76c..0000000000 --- a/packages/react-instantsearch-core/src/core/translatable.js +++ /dev/null @@ -1,52 +0,0 @@ -import React, { Component } from 'react'; - -const withKeysPropType = (keys) => (props, propName, componentName) => { - const prop = props[propName]; - if (prop) { - // eslint-disable-next-line no-restricted-syntax - for (const key of Object.keys(prop)) { - if (keys.indexOf(key) === -1) { - return new Error( - `Unknown \`${propName}\` key \`${key}\`. Check the render method ` + - `of \`${componentName}\`.` - ); - } - } - } - return undefined; -}; - -export default function translatable(defaultTranslations) { - return (Composed) => { - class Translatable extends Component { - translate = (key, ...params) => { - const { translations } = this.props; - - const translation = - translations && translations.hasOwnProperty(key) - ? translations[key] - : defaultTranslations[key]; - - if (typeof translation === 'function') { - return translation(...params); - } - - return translation; - }; - - render() { - return ; - } - } - - const name = Composed.displayName || Composed.name || 'UnknownComponent'; - - Translatable.displayName = `Translatable(${name})`; - - Translatable.propTypes = { - translations: withKeysPropType(Object.keys(defaultTranslations)), - }; - - return Translatable; - }; -} diff --git a/packages/react-instantsearch-core/src/core/utils.ts b/packages/react-instantsearch-core/src/core/utils.ts deleted file mode 100644 index 283615ed90..0000000000 --- a/packages/react-instantsearch-core/src/core/utils.ts +++ /dev/null @@ -1,162 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/unbound-method -const hasOwn = Object.prototype.hasOwnProperty; - -// From https://github.com/reactjs/react-redux/blob/master/src/utils/shallowEqual.js -export const shallowEqual = (objA: any, objB: any) => { - if (objA === objB) { - return true; - } - - const keysA = Object.keys(objA); - const keysB = Object.keys(objB); - - if (keysA.length !== keysB.length) { - return false; - } - - // Test for A's keys different from B. - for (let i = 0; i < keysA.length; i++) { - if (!hasOwn.call(objB, keysA[i]) || objA[keysA[i]] !== objB[keysA[i]]) { - return false; - } - } - - return true; -}; - -export const getDisplayName = (Component: any) => - Component.displayName || Component.name || 'UnknownComponent'; - -const resolved = Promise.resolve(); -export const defer = (f: any) => { - resolved.then(f); -}; - -const isPlainObject = (value: unknown): value is object => - typeof value === 'object' && value !== null && !Array.isArray(value); - -export const removeEmptyKey = (obj: Record) => { - Object.keys(obj).forEach((key) => { - const value = obj[key]; - - if (!isPlainObject(value)) { - return; - } - - if (!objectHasKeys(value)) { - delete obj[key]; - } else { - removeEmptyKey(value); - } - }); - - return obj; -}; - -export const removeEmptyArraysFromObject = (obj: Record) => { - Object.keys(obj).forEach((key) => { - const value = obj[key]; - - if (Array.isArray(value) && value.length === 0) { - delete obj[key]; - } - }); - - return obj; -}; - -export function addAbsolutePositions( - hits: any[], - hitsPerPage: number, - page: number -) { - return hits.map((hit, index) => ({ - ...hit, - __position: hitsPerPage * page + index + 1, - })); -} - -export function addQueryID(hits: any[], queryID: string) { - if (!queryID) { - return hits; - } - return hits.map((hit) => ({ - ...hit, - __queryID: queryID, - })); -} - -export function find( - array: TItem[], - comparator: (item: TItem) => boolean -): TItem | undefined { - if (!Array.isArray(array)) { - return undefined; - } - - for (let i = 0; i < array.length; i++) { - if (comparator(array[i])) { - return array[i]; - } - } - return undefined; -} - -export function objectHasKeys(object: object | undefined) { - return object && Object.keys(object).length > 0; -} - -// https://github.com/babel/babel/blob/3aaafae053fa75febb3aa45d45b6f00646e30ba4/packages/babel-helpers/src/helpers.js#L604-L620 -export function omit( - source: Record, - excluded: string[] -): Record { - if (source === null || source === undefined) { - return {}; - } - const target: Record = {}; - const sourceKeys = Object.keys(source); - for (let i = 0; i < sourceKeys.length; i++) { - const key = sourceKeys[i]; - if (excluded.indexOf(key) >= 0) { - // eslint-disable-next-line no-continue - continue; - } - target[key] = source[key]; - } - return target; -} - -/** - * Retrieve the value at a path of the object: - * - * @example - * getPropertyByPath( - * { test: { this: { function: [{ now: { everyone: true } }] } } }, - * 'test.this.function[0].now.everyone' - * ); // true - * - * getPropertyByPath( - * { test: { this: { function: [{ now: { everyone: true } }] } } }, - * ['test', 'this', 'function', 0, 'now', 'everyone'] - * ); // true - * - * @param object Source object to query - * @param path either an array of properties, or a string form of the properties, separated by . - */ -export const getPropertyByPath = ( - object: Record, - path: string[] | string -): any => - (Array.isArray(path) - ? path - : path.replace(/\[(\d+)]/g, '.$1').split('.') - ).reduce((current, key) => (current ? current[key] : undefined), object); - -export function getObjectType(object: unknown): string { - return Object.prototype.toString.call(object).slice(8, -1); -} - -export function unescapeFacetValue(value: string): string { - return value.replace(/^\\-/, '-'); -} diff --git a/packages/react-instantsearch-core/src/core/version.js b/packages/react-instantsearch-core/src/core/version.js deleted file mode 100644 index ecdab9c92b..0000000000 --- a/packages/react-instantsearch-core/src/core/version.js +++ /dev/null @@ -1 +0,0 @@ -export default '6.40.4'; diff --git a/packages/react-instantsearch-hooks/src/hooks/__tests__/useConnector.test.tsx b/packages/react-instantsearch-core/src/hooks/__tests__/useConnector.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/hooks/__tests__/useConnector.test.tsx rename to packages/react-instantsearch-core/src/hooks/__tests__/useConnector.test.tsx diff --git a/packages/react-instantsearch-hooks/src/hooks/__tests__/useInstantSearch.test.tsx b/packages/react-instantsearch-core/src/hooks/__tests__/useInstantSearch.test.tsx similarity index 91% rename from packages/react-instantsearch-hooks/src/hooks/__tests__/useInstantSearch.test.tsx rename to packages/react-instantsearch-core/src/hooks/__tests__/useInstantSearch.test.tsx index 165bc1e7dc..e3dd06b3cf 100644 --- a/packages/react-instantsearch-hooks/src/hooks/__tests__/useInstantSearch.test.tsx +++ b/packages/react-instantsearch-core/src/hooks/__tests__/useInstantSearch.test.tsx @@ -5,7 +5,7 @@ import { createAlgoliaSearchClient } from '@instantsearch/mocks'; import { createInstantSearchTestWrapper, - InstantSearchHooksTestWrapper, + InstantSearchTestWrapper, wait, } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; @@ -13,7 +13,7 @@ import { renderHook } from '@testing-library/react-hooks'; import userEvent from '@testing-library/user-event'; import { AlgoliaSearchHelper, SearchResults } from 'algoliasearch-helper'; import React, { useEffect } from 'react'; -import { SearchBox } from 'react-instantsearch-hooks-web'; +import { SearchBox } from 'react-instantsearch'; import { useInstantSearch } from '../useInstantSearch'; @@ -28,7 +28,7 @@ describe('useInstantSearch', () => { expect(result.error?.message).toMatchInlineSnapshot(` "[InstantSearch] Hooks must be used inside the component. - They are not compatible with the \`react-instantsearch-core\` and \`react-instantsearch-dom\` packages, so make sure to use the component from \`react-instantsearch-hooks\`." + They are not compatible with the \`react-instantsearch-core@6.x\` and \`react-instantsearch-dom\` packages, so make sure to use the component from \`react-instantsearch-core@7.x\`." `); }); }); @@ -114,9 +114,9 @@ describe('useInstantSearch', () => { } const { findByTestId } = render( - + - + ); const button = await findByTestId('button'); @@ -153,9 +153,9 @@ describe('useInstantSearch', () => { } const { findByTestId } = render( - + - + ); const button = await findByTestId('button'); @@ -192,10 +192,10 @@ describe('useInstantSearch', () => { function App() { return ( - + - + ); } @@ -262,10 +262,10 @@ describe('useInstantSearch', () => { } const { getByTestId } = render( - + - + ); const refreshButton = getByTestId('refresh-button'); @@ -297,10 +297,10 @@ describe('useInstantSearch', () => { describe('status', () => { test('initial status: idle', () => { const App = () => ( - + - + ); const { getByTestId } = render(); @@ -310,12 +310,10 @@ describe('useInstantSearch', () => { test('turns to loading and idle when searching', async () => { const App = () => ( - + - + ); const { getByTestId, getByPlaceholderText } = render(); @@ -335,13 +333,13 @@ describe('useInstantSearch', () => { test('turns to loading, stalled and idle when searching slowly', async () => { const App = () => ( - - + ); const { getByTestId, getByPlaceholderText } = render(); @@ -371,11 +369,11 @@ describe('useInstantSearch', () => { }); const App = () => ( - + {/* has catchError, as the real error can not be asserted upon */} - + ); const { getByTestId, getByPlaceholderText } = render(); diff --git a/packages/react-instantsearch-hooks/src/hooks/useConnector.ts b/packages/react-instantsearch-core/src/hooks/useConnector.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/hooks/useConnector.ts rename to packages/react-instantsearch-core/src/hooks/useConnector.ts diff --git a/packages/react-instantsearch-hooks/src/hooks/useInstantSearch.ts b/packages/react-instantsearch-core/src/hooks/useInstantSearch.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/hooks/useInstantSearch.ts rename to packages/react-instantsearch-core/src/hooks/useInstantSearch.ts diff --git a/packages/react-instantsearch-core/src/index.ts b/packages/react-instantsearch-core/src/index.ts index 7f99b00341..67f24e3b87 100644 --- a/packages/react-instantsearch-core/src/index.ts +++ b/packages/react-instantsearch-core/src/index.ts @@ -1,93 +1,31 @@ -// Core -export { default as createConnector } from './core/createConnector'; -export { - instantSearchContext, - InstantSearchConsumer, - InstantSearchProvider, -} from './core/context'; - -// Utils -// @ts-ignore not yet typed -export { HIGHLIGHT_TAGS } from './core/highlight'; -// @ts-ignore not yet typed -export { default as version } from './core/version'; -// @ts-ignore not yet typed -export { default as translatable } from './core/translatable'; - -// Widgets -// @ts-ignore not yet typed -export { default as Configure } from './widgets/Configure'; -export { default as ExperimentalConfigureRelatedItems } from './widgets/ConfigureRelatedItems'; - -import { default as connectDynamicWidgets } from './connectors/connectDynamicWidgets'; -import { default as DynamicWidgets } from './widgets/DynamicWidgets'; -/** @deprecated use DynamicWidgets */ -const ExperimentalDynamicWidgets = DynamicWidgets; -export { ExperimentalDynamicWidgets, DynamicWidgets }; - -export { default as QueryRuleContext } from './widgets/QueryRuleContext'; -export { default as Index } from './widgets/Index'; -export { default as InstantSearch } from './widgets/InstantSearch'; - -// Connectors -// @ts-ignore not yet typed -export { default as connectAutoComplete } from './connectors/connectAutoComplete'; -// @ts-ignore not yet typed -export { default as connectBreadcrumb } from './connectors/connectBreadcrumb'; -// @ts-ignore not yet typed -export { default as connectConfigure } from './connectors/connectConfigure'; -export { default as EXPERIMENTAL_connectConfigureRelatedItems } from './connectors/connectConfigureRelatedItems'; -// @ts-ignore not yet typed -export { default as connectCurrentRefinements } from './connectors/connectCurrentRefinements'; - -/** @deprecated use connectDynamicWidgets */ -const EXPERIMENTAL_connectDynamicWidgets = connectDynamicWidgets; -export { connectDynamicWidgets, EXPERIMENTAL_connectDynamicWidgets }; - -// @ts-ignore not yet typed -export { default as connectGeoSearch } from './connectors/connectGeoSearch'; -// @ts-ignore not yet typed -export { default as connectHierarchicalMenu } from './connectors/connectHierarchicalMenu'; -// @ts-ignore not yet typed -export { default as connectHighlight } from './connectors/connectHighlight'; -// @ts-ignore not yet typed -export { default as connectHits } from './connectors/connectHits'; -// @ts-ignore not yet typed -export { default as connectHitsPerPage } from './connectors/connectHitsPerPage'; -// @ts-ignore not yet typed -export { default as connectInfiniteHits } from './connectors/connectInfiniteHits'; -// @ts-ignore not yet typed -export { default as connectMenu } from './connectors/connectMenu'; -// @ts-ignore not yet typed -export { default as connectNumericMenu } from './connectors/connectNumericMenu'; -// @ts-ignore not yet typed -export { default as connectPagination } from './connectors/connectPagination'; -// @ts-ignore not yet typed -export { default as connectPoweredBy } from './connectors/connectPoweredBy'; -// @ts-ignore not yet typed -export { default as connectQueryRules } from './connectors/connectQueryRules'; -// @ts-ignore not yet typed -export { default as connectRange } from './connectors/connectRange'; -// @ts-ignore not yet typed -export { default as connectRefinementList } from './connectors/connectRefinementList'; -// @ts-ignore not yet typed -export { default as connectScrollTo } from './connectors/connectScrollTo'; -// @ts-ignore not yet typed -export { default as connectSearchBox } from './connectors/connectSearchBox'; -// @ts-ignore not yet typed -export { default as connectRelevantSort } from './connectors/connectRelevantSort'; -// @ts-ignore not yet typed -export { default as connectSortBy } from './connectors/connectSortBy'; -// @ts-ignore not yet typed -export { default as connectStateResults } from './connectors/connectStateResults'; -// @ts-ignore not yet typed -export { default as connectStats } from './connectors/connectStats'; -// @ts-ignore not yet typed -export { default as connectToggleRefinement } from './connectors/connectToggleRefinement'; -// @ts-ignore not yet typed -export { default as connectHitInsights } from './connectors/connectHitInsights'; -// @ts-ignore not yet typed -export { default as connectVoiceSearch } from './connectors/connectVoiceSearch'; - -// Types -export * from './types'; +export { default as version } from './version'; +export * from './components/Configure'; +export * from './components/DynamicWidgets'; +export * from './components/Index'; +export * from './components/InstantSearch'; +export * from './components/InstantSearchServerContext'; +export * from './components/InstantSearchSSRProvider'; +export * from './connectors/useBreadcrumb'; +export * from './connectors/useClearRefinements'; +export * from './connectors/useConfigure'; +export * from './connectors/useCurrentRefinements'; +export * from './connectors/useDynamicWidgets'; +export * from './connectors/useGeoSearch'; +export * from './connectors/useHierarchicalMenu'; +export * from './connectors/useHits'; +export * from './connectors/useHitsPerPage'; +export * from './connectors/useInfiniteHits'; +export * from './connectors/useMenu'; +export * from './connectors/useNumericMenu'; +export * from './connectors/usePagination'; +export * from './connectors/usePoweredBy'; +export * from './connectors/useQueryRules'; +export * from './connectors/useRange'; +export * from './connectors/useRefinementList'; +export * from './connectors/useSearchBox'; +export * from './connectors/useSortBy'; +export * from './connectors/useStats'; +export * from './connectors/useToggleRefinement'; +export * from './hooks/useConnector'; +export * from './hooks/useInstantSearch'; +export * from './server'; diff --git a/packages/react-instantsearch-hooks/src/lib/IndexContext.ts b/packages/react-instantsearch-core/src/lib/IndexContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/IndexContext.ts rename to packages/react-instantsearch-core/src/lib/IndexContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/InstantSearchContext.ts b/packages/react-instantsearch-core/src/lib/InstantSearchContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/InstantSearchContext.ts rename to packages/react-instantsearch-core/src/lib/InstantSearchContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/InstantSearchSSRContext.ts b/packages/react-instantsearch-core/src/lib/InstantSearchSSRContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/InstantSearchSSRContext.ts rename to packages/react-instantsearch-core/src/lib/InstantSearchSSRContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/IndexContext.test.tsx b/packages/react-instantsearch-core/src/lib/__tests__/IndexContext.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/IndexContext.test.tsx rename to packages/react-instantsearch-core/src/lib/__tests__/IndexContext.test.tsx diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/InstantSearchContext.test.tsx b/packages/react-instantsearch-core/src/lib/__tests__/InstantSearchContext.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/InstantSearchContext.test.tsx rename to packages/react-instantsearch-core/src/lib/__tests__/InstantSearchContext.test.tsx diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/InstantSearchSSRContext.test.tsx b/packages/react-instantsearch-core/src/lib/__tests__/InstantSearchSSRContext.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/InstantSearchSSRContext.test.tsx rename to packages/react-instantsearch-core/src/lib/__tests__/InstantSearchSSRContext.test.tsx diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/createSearchResults.test.ts b/packages/react-instantsearch-core/src/lib/__tests__/createSearchResults.test.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/createSearchResults.test.ts rename to packages/react-instantsearch-core/src/lib/__tests__/createSearchResults.test.ts diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/dequal.test.ts b/packages/react-instantsearch-core/src/lib/__tests__/dequal.test.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/dequal.test.ts rename to packages/react-instantsearch-core/src/lib/__tests__/dequal.test.ts diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/invariant.test.ts b/packages/react-instantsearch-core/src/lib/__tests__/invariant.test.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/invariant.test.ts rename to packages/react-instantsearch-core/src/lib/__tests__/invariant.test.ts diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/useSearchResults.test.tsx b/packages/react-instantsearch-core/src/lib/__tests__/useSearchResults.test.tsx similarity index 97% rename from packages/react-instantsearch-hooks/src/lib/__tests__/useSearchResults.test.tsx rename to packages/react-instantsearch-core/src/lib/__tests__/useSearchResults.test.tsx index f8d5dada08..6870ee9689 100644 --- a/packages/react-instantsearch-hooks/src/lib/__tests__/useSearchResults.test.tsx +++ b/packages/react-instantsearch-core/src/lib/__tests__/useSearchResults.test.tsx @@ -6,7 +6,7 @@ import { createInstantSearchTestWrapper } from '@instantsearch/testutils'; import { renderHook } from '@testing-library/react-hooks'; import { AlgoliaSearchHelper, SearchResults } from 'algoliasearch-helper'; import React from 'react'; -import { SearchBox } from 'react-instantsearch-hooks-web'; +import { SearchBox } from 'react-instantsearch'; import { useSearchResults } from '../useSearchResults'; diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/useSearchState.test.tsx b/packages/react-instantsearch-core/src/lib/__tests__/useSearchState.test.tsx similarity index 95% rename from packages/react-instantsearch-hooks/src/lib/__tests__/useSearchState.test.tsx rename to packages/react-instantsearch-core/src/lib/__tests__/useSearchState.test.tsx index acc0cf479b..5021e7bb4e 100644 --- a/packages/react-instantsearch-hooks/src/lib/__tests__/useSearchState.test.tsx +++ b/packages/react-instantsearch-core/src/lib/__tests__/useSearchState.test.tsx @@ -4,7 +4,7 @@ import { createInstantSearchTestWrapper, - InstantSearchHooksTestWrapper, + InstantSearchTestWrapper, } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; @@ -91,9 +91,9 @@ describe('useSearchState', () => { } const { getByRole, getByTestId } = render( - + - + ); const button = getByRole('button'); const uiState = getByTestId('uiState'); @@ -140,9 +140,9 @@ describe('useSearchState', () => { } const { getByRole, getByTestId } = render( - + - + ); const button = getByRole('button'); const uiState = getByTestId('uiState'); @@ -192,9 +192,9 @@ describe('useSearchState', () => { } const { getByRole, getByTestId } = render( - + - + ); const button = getByRole('button'); const indexUiState = getByTestId('indexUiState'); @@ -238,9 +238,9 @@ describe('useSearchState', () => { } const { getByRole, getByTestId } = render( - + - + ); const button = getByRole('button'); const indexUiState = getByTestId('indexUiState'); diff --git a/packages/react-instantsearch-hooks/src/lib/__tests__/warn.test.ts b/packages/react-instantsearch-core/src/lib/__tests__/warn.test.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/__tests__/warn.test.ts rename to packages/react-instantsearch-core/src/lib/__tests__/warn.test.ts diff --git a/packages/react-instantsearch-hooks/src/lib/createSearchResults.ts b/packages/react-instantsearch-core/src/lib/createSearchResults.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/createSearchResults.ts rename to packages/react-instantsearch-core/src/lib/createSearchResults.ts diff --git a/packages/react-instantsearch-hooks/src/lib/dequal.ts b/packages/react-instantsearch-core/src/lib/dequal.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/dequal.ts rename to packages/react-instantsearch-core/src/lib/dequal.ts diff --git a/packages/react-instantsearch-hooks/src/lib/getIndexSearchResults.ts b/packages/react-instantsearch-core/src/lib/getIndexSearchResults.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/getIndexSearchResults.ts rename to packages/react-instantsearch-core/src/lib/getIndexSearchResults.ts diff --git a/packages/react-instantsearch-hooks/src/lib/invariant.ts b/packages/react-instantsearch-core/src/lib/invariant.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/invariant.ts rename to packages/react-instantsearch-core/src/lib/invariant.ts diff --git a/packages/react-instantsearch-hooks/src/lib/noop.ts b/packages/react-instantsearch-core/src/lib/noop.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/noop.ts rename to packages/react-instantsearch-core/src/lib/noop.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useForceUpdate.ts b/packages/react-instantsearch-core/src/lib/useForceUpdate.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useForceUpdate.ts rename to packages/react-instantsearch-core/src/lib/useForceUpdate.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useIndex.ts b/packages/react-instantsearch-core/src/lib/useIndex.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useIndex.ts rename to packages/react-instantsearch-core/src/lib/useIndex.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useIndexContext.ts b/packages/react-instantsearch-core/src/lib/useIndexContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useIndexContext.ts rename to packages/react-instantsearch-core/src/lib/useIndexContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useInstantSearchApi.ts b/packages/react-instantsearch-core/src/lib/useInstantSearchApi.ts similarity index 97% rename from packages/react-instantsearch-hooks/src/lib/useInstantSearchApi.ts rename to packages/react-instantsearch-core/src/lib/useInstantSearchApi.ts index 77b3439765..5506e48ea1 100644 --- a/packages/react-instantsearch-hooks/src/lib/useInstantSearchApi.ts +++ b/packages/react-instantsearch-core/src/lib/useInstantSearchApi.ts @@ -18,7 +18,7 @@ import type { const defaultUserAgents = [ `react (${ReactVersion})`, `react-instantsearch (${version})`, - `react-instantsearch-hooks (${version})`, + `react-instantsearch-core (${version})`, ]; const serverUserAgent = `react-instantsearch-server (${version})`; const nextUserAgent = (nextVersion?: string) => @@ -137,7 +137,7 @@ export function useInstantSearchApi( if (prevProps.searchClient !== props.searchClient) { warn( false, - 'The `searchClient` prop of `` changed between renders, which may cause more search requests than necessary. If this is an unwanted behavior, please provide a stable reference: https://www.algolia.com/doc/api-reference/widgets/instantsearch/react-hooks/#widget-param-searchclient' + 'The `searchClient` prop of `` changed between renders, which may cause more search requests than necessary. If this is an unwanted behavior, please provide a stable reference: https://www.algolia.com/doc/api-reference/widgets/instantsearch/react/#widget-param-searchclient' ); addAlgoliaAgents(props.searchClient, [ @@ -257,9 +257,9 @@ function warnNextRouter( warn( isUsingNextRouter, ` -You are using Next.js with InstantSearch without the "react-instantsearch-hooks-router-nextjs" package. +You are using Next.js with InstantSearch without the "react-instantsearch-router-nextjs" package. This package is recommended to make the routing work correctly with Next.js. -Please check its usage instructions: https://github.com/algolia/instantsearch/tree/master/packages/react-instantsearch-hooks-router-nextjs +Please check its usage instructions: https://github.com/algolia/instantsearch/tree/master/packages/react-instantsearch-router-nextjs You can ignore this warning if you are using a custom router that suits your needs, it won't be outputted in production builds.` ); diff --git a/packages/react-instantsearch-hooks/src/lib/useInstantSearchContext.ts b/packages/react-instantsearch-core/src/lib/useInstantSearchContext.ts similarity index 84% rename from packages/react-instantsearch-hooks/src/lib/useInstantSearchContext.ts rename to packages/react-instantsearch-core/src/lib/useInstantSearchContext.ts index 8b4e18c9dc..af1d102139 100644 --- a/packages/react-instantsearch-hooks/src/lib/useInstantSearchContext.ts +++ b/packages/react-instantsearch-core/src/lib/useInstantSearchContext.ts @@ -22,7 +22,7 @@ export function useInstantSearchContext< invariant( search !== null, 'Hooks must be used inside the component.\n\n' + - 'They are not compatible with the `react-instantsearch-core` and `react-instantsearch-dom` packages, so make sure to use the component from `react-instantsearch-hooks`.' + 'They are not compatible with the `react-instantsearch-core@6.x` and `react-instantsearch-dom` packages, so make sure to use the component from `react-instantsearch-core@7.x`.' ); return search; diff --git a/packages/react-instantsearch-hooks/src/lib/useInstantSearchSSRContext.ts b/packages/react-instantsearch-core/src/lib/useInstantSearchSSRContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useInstantSearchSSRContext.ts rename to packages/react-instantsearch-core/src/lib/useInstantSearchSSRContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useInstantSearchServerContext.ts b/packages/react-instantsearch-core/src/lib/useInstantSearchServerContext.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useInstantSearchServerContext.ts rename to packages/react-instantsearch-core/src/lib/useInstantSearchServerContext.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useIsomorphicLayoutEffect.ts b/packages/react-instantsearch-core/src/lib/useIsomorphicLayoutEffect.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useIsomorphicLayoutEffect.ts rename to packages/react-instantsearch-core/src/lib/useIsomorphicLayoutEffect.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useSearchResults.ts b/packages/react-instantsearch-core/src/lib/useSearchResults.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useSearchResults.ts rename to packages/react-instantsearch-core/src/lib/useSearchResults.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useSearchState.ts b/packages/react-instantsearch-core/src/lib/useSearchState.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useSearchState.ts rename to packages/react-instantsearch-core/src/lib/useSearchState.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useStableValue.ts b/packages/react-instantsearch-core/src/lib/useStableValue.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useStableValue.ts rename to packages/react-instantsearch-core/src/lib/useStableValue.ts diff --git a/packages/react-instantsearch-hooks/src/lib/useWidget.ts b/packages/react-instantsearch-core/src/lib/useWidget.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/useWidget.ts rename to packages/react-instantsearch-core/src/lib/useWidget.ts diff --git a/packages/react-instantsearch-hooks/src/lib/warn.ts b/packages/react-instantsearch-core/src/lib/warn.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/lib/warn.ts rename to packages/react-instantsearch-core/src/lib/warn.ts diff --git a/packages/react-instantsearch-hooks-server/src/__tests__/__snapshots__/getServerState.test.tsx.snap b/packages/react-instantsearch-core/src/server/__tests__/__snapshots__/getServerState.test.tsx.snap similarity index 100% rename from packages/react-instantsearch-hooks-server/src/__tests__/__snapshots__/getServerState.test.tsx.snap rename to packages/react-instantsearch-core/src/server/__tests__/__snapshots__/getServerState.test.tsx.snap diff --git a/packages/react-instantsearch-hooks-server/src/__tests__/getServerState.test.tsx b/packages/react-instantsearch-core/src/server/__tests__/getServerState.test.tsx similarity index 98% rename from packages/react-instantsearch-hooks-server/src/__tests__/getServerState.test.tsx rename to packages/react-instantsearch-core/src/server/__tests__/getServerState.test.tsx index e2a916dd8c..728e461769 100644 --- a/packages/react-instantsearch-hooks-server/src/__tests__/getServerState.test.tsx +++ b/packages/react-instantsearch-core/src/server/__tests__/getServerState.test.tsx @@ -11,6 +11,7 @@ import { } from '@instantsearch/mocks'; import React, { version as ReactVersion } from 'react'; import { renderToString } from 'react-dom/server'; +import { Hits, RefinementList } from 'react-instantsearch'; import { InstantSearch, InstantSearchSSRProvider, @@ -18,8 +19,7 @@ import { DynamicWidgets, version, useSearchBox, -} from 'react-instantsearch-hooks'; -import { Hits, RefinementList } from 'react-instantsearch-hooks-web'; +} from 'react-instantsearch-core'; import { getServerState } from '../getServerState'; @@ -28,7 +28,7 @@ import type { Hit as AlgoliaHit } from 'instantsearch.js'; import type { InstantSearchServerState, InstantSearchProps, -} from 'react-instantsearch-hooks'; +} from 'react-instantsearch-core'; function SearchBox() { const { query } = useSearchBox(); @@ -204,7 +204,7 @@ describe('getServerState', () => { `react-instantsearch (${version})` ); expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch-hooks (${version})` + `react-instantsearch-core (${version})` ); expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( `react-instantsearch-server (${version})` diff --git a/packages/react-instantsearch-hooks-server/src/getServerState.tsx b/packages/react-instantsearch-core/src/server/getServerState.tsx similarity index 96% rename from packages/react-instantsearch-hooks-server/src/getServerState.tsx rename to packages/react-instantsearch-core/src/server/getServerState.tsx index 84591db904..d2c18defa2 100644 --- a/packages/react-instantsearch-hooks-server/src/getServerState.tsx +++ b/packages/react-instantsearch-core/src/server/getServerState.tsx @@ -4,17 +4,15 @@ import { } from 'instantsearch.js/es/lib/server'; import { walkIndex } from 'instantsearch.js/es/lib/utils'; import React from 'react'; -import { - InstantSearchServerContext, - InstantSearchSSRProvider, -} from 'react-instantsearch-hooks'; -import type { InstantSearch, UiState } from 'instantsearch.js'; -import type { ReactNode } from 'react'; +import { InstantSearchServerContext, InstantSearchSSRProvider } from '..'; + import type { InstantSearchServerContextApi, InstantSearchServerState, -} from 'react-instantsearch-hooks'; +} from '..'; +import type { InstantSearch, UiState } from 'instantsearch.js'; +import type { ReactNode } from 'react'; type SearchRef = { current: InstantSearch | undefined }; diff --git a/packages/react-instantsearch-hooks-server/src/index.ts b/packages/react-instantsearch-core/src/server/index.ts similarity index 100% rename from packages/react-instantsearch-hooks-server/src/index.ts rename to packages/react-instantsearch-core/src/server/index.ts diff --git a/packages/react-instantsearch-core/src/types/algoliasearch.ts b/packages/react-instantsearch-core/src/types/algoliasearch.ts deleted file mode 100644 index bbf2b3c567..0000000000 --- a/packages/react-instantsearch-core/src/types/algoliasearch.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Custom types to support both algoliasearch -// `v3` and algoliasearch `v4` clients. - -import type * as ClientSearch from '@algolia/client-search'; -import type algoliasearch from 'algoliasearch/lite'; -import type * as AlgoliaSearch from 'algoliasearch/lite'; -/** @ts-ignore */ - -/** @ts-ignore */ -type SearchResponseV3 = AlgoliaSearch.Response; -/** @ts-ignore */ -type SearchResponseV4 = ClientSearch.SearchResponse; - -type DummySearchClientV4 = { - readonly addAlgoliaAgent: (segment: string, version?: string) => void; -}; - -type SearchResponse = ReturnType< - typeof algoliasearch -> extends DummySearchClientV4 - ? SearchResponseV4 - : SearchResponseV3; - -export interface MultiResponse { - results: Array>; -} diff --git a/packages/react-instantsearch-core/src/types/index.ts b/packages/react-instantsearch-core/src/types/index.ts deleted file mode 100644 index 0274a75363..0000000000 --- a/packages/react-instantsearch-core/src/types/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './translatable'; diff --git a/packages/react-instantsearch-core/src/types/translatable.ts b/packages/react-instantsearch-core/src/types/translatable.ts deleted file mode 100644 index 03f8f7c34b..0000000000 --- a/packages/react-instantsearch-core/src/types/translatable.ts +++ /dev/null @@ -1 +0,0 @@ -export type Translate = (key: string, ...params: any[]) => string; diff --git a/packages/react-instantsearch-hooks/src/version.ts b/packages/react-instantsearch-core/src/version.ts similarity index 100% rename from packages/react-instantsearch-hooks/src/version.ts rename to packages/react-instantsearch-core/src/version.ts diff --git a/packages/react-instantsearch-core/src/widgets/Configure.js b/packages/react-instantsearch-core/src/widgets/Configure.js deleted file mode 100644 index 84314ed150..0000000000 --- a/packages/react-instantsearch-core/src/widgets/Configure.js +++ /dev/null @@ -1,43 +0,0 @@ -import connectConfigure from '../connectors/connectConfigure'; - -/** - * Configure is a widget that lets you provide raw search parameters - * to the Algolia API. - * - * Any of the props added to this widget will be forwarded to Algolia. For more information - * on the different parameters that can be set, have a look at the - * [reference](https://www.algolia.com/doc/api-client/javascript/search#search-parameters). - * - * This widget can be used either with react-dom and react-native. It will not render anything - * on screen, only configure some parameters. - * - * Read more in the [Search parameters](guide/Search_parameters.html) guide. - * @name Configure - * @kind widget - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, Configure, Hits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ - -export default connectConfigure( - function Configure() { - return null; - }, - { $$widgetType: 'ais.configure' } -); diff --git a/packages/react-instantsearch-core/src/widgets/ConfigureRelatedItems.tsx b/packages/react-instantsearch-core/src/widgets/ConfigureRelatedItems.tsx deleted file mode 100644 index aa8ffe7484..0000000000 --- a/packages/react-instantsearch-core/src/widgets/ConfigureRelatedItems.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import PropTypes from 'prop-types'; - -import connectConfigureRelatedItems from '../connectors/connectConfigureRelatedItems'; - -function ConfigureRelatedItems() { - return null; -} - -ConfigureRelatedItems.propTypes = { - hit: PropTypes.object.isRequired, - matchingPatterns: PropTypes.object.isRequired, - transformSearchParameters: PropTypes.func, -}; - -export default connectConfigureRelatedItems(ConfigureRelatedItems, { - $$widgetType: 'ais.configureRelatedItems', -}); diff --git a/packages/react-instantsearch-core/src/widgets/DynamicWidgets.tsx b/packages/react-instantsearch-core/src/widgets/DynamicWidgets.tsx deleted file mode 100644 index e3a72fc457..0000000000 --- a/packages/react-instantsearch-core/src/widgets/DynamicWidgets.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import React, { Fragment } from 'react'; - -import connectDynamicWidgets from '../connectors/connectDynamicWidgets'; -import { getDisplayName } from '../core/utils'; - -import type { ComponentType, ReactElement, ReactNode } from 'react'; - -function isReactElement(element: any): element is ReactElement { - return typeof element === 'object' && element.props; -} - -function getAttribute(element: ReactNode): string | undefined { - if (!isReactElement(element)) { - return undefined; - } - - if (element.props.attribute) { - return element.props.attribute; - } - if (Array.isArray(element.props.attributes)) { - return element.props.attributes[0]; - } - if (element.props.children) { - return getAttribute(React.Children.only(element.props.children)); - } - - return undefined; -} - -type DynamicWidgetsProps = { - children: ReactNode; - attributesToRender: string[]; - fallbackComponent?: ComponentType<{ attribute: string }>; -}; - -function DynamicWidgets({ - children, - attributesToRender, - fallbackComponent: Fallback = () => null, -}: DynamicWidgetsProps) { - const widgets: Map = new Map(); - - React.Children.forEach(children, (child) => { - const attribute = getAttribute(child); - if (!attribute) { - throw new Error( - `Could not find "attribute" prop for ${getDisplayName(child)}.` - ); - } - widgets.set(attribute, child); - }); - - // on initial render this will be empty, but React InstantSearch keeps - // search state for unmounted components in place, so routing works. - return ( - <> - {attributesToRender.map((attribute) => ( - - {widgets.get(attribute) || } - - ))} - - ); -} - -export default connectDynamicWidgets(DynamicWidgets, { - $$widgetType: 'ais.dynamicWidgets', -}); diff --git a/packages/react-instantsearch-core/src/widgets/Index.tsx b/packages/react-instantsearch-core/src/widgets/Index.tsx deleted file mode 100644 index 77066c9e43..0000000000 --- a/packages/react-instantsearch-core/src/widgets/Index.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component, Children } from 'react'; - -import { InstantSearchConsumer, IndexProvider } from '../core/context'; - -import type { InstantSearchContext, IndexContext } from '../core/context'; -import type { SearchParameters } from 'algoliasearch-helper'; - -function getIndexContext(props: Props): IndexContext { - return { - targetedIndex: props.indexId, - }; -} - -type Props = { - indexName: string; - indexId: string; - children?: React.ReactNode; -}; - -type InnerProps = Props & { contextValue: InstantSearchContext }; - -type State = { - indexContext: IndexContext; -}; - -/** - * The component that allows you to apply widgets to a dedicated index. It's - * useful if you want to build an interface that targets multiple indices. - * - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, Index, SearchBox, Hits, Configure } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * - * - * - * - * - * - * ); - */ -class Index extends Component { - static propTypes = { - indexName: PropTypes.string.isRequired, - indexId: PropTypes.string.isRequired, - children: PropTypes.node, - }; - - static displayName = 'AlgoliaIndex'; - static $$type = 'ais.index'; - static $$widgetType = 'ais.index'; - - static getDerivedStateFromProps(props: InnerProps) { - return { - indexContext: getIndexContext(props), - }; - } - - state = { - indexContext: getIndexContext(this.props), - }; - - unregisterWidget?: () => void; - - constructor(props: InnerProps) { - super(props); - - this.props.contextValue.onSearchParameters( - this.getSearchParameters.bind(this), - { - ais: this.props.contextValue, - multiIndexContext: this.state.indexContext, - }, - this.props, - undefined, - Index.displayName - ); - } - - componentDidMount() { - this.unregisterWidget = - this.props.contextValue.widgetsManager.registerWidget(this); - } - - componentDidUpdate(prevProps: InnerProps) { - if (this.props.indexName !== prevProps.indexName) { - this.props.contextValue.widgetsManager.update(); - } - } - - componentWillUnmount() { - if (typeof this.unregisterWidget === 'function') { - this.unregisterWidget(); - } - } - - getSearchParameters(searchParameters: SearchParameters, props: InnerProps) { - return searchParameters.setIndex( - this.props ? this.props.indexName : props.indexName - ); - } - - render() { - const childrenCount = Children.count(this.props.children); - if (childrenCount === 0) { - return null; - } - return ( - - {this.props.children} - - ); - } -} - -type IndexWrapperProps = { - indexName: string; - indexId?: string; -}; - -const IndexWrapper: React.FC = (props) => { - const inferredIndexId = props.indexName; - return ( - - {(contextValue) => ( - - )} - - ); -}; - -IndexWrapper.propTypes = { - indexName: PropTypes.string.isRequired, - indexId: PropTypes.string, -}; - -export const IndexComponentWithoutContext = Index; -export default IndexWrapper; diff --git a/packages/react-instantsearch-core/src/widgets/InstantSearch.tsx b/packages/react-instantsearch-core/src/widgets/InstantSearch.tsx deleted file mode 100644 index 27f8fd1721..0000000000 --- a/packages/react-instantsearch-core/src/widgets/InstantSearch.tsx +++ /dev/null @@ -1,337 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component, Children } from 'react'; -import isEqual from 'react-fast-compare'; - -import { InstantSearchProvider } from '../core/context'; -import createInstantSearchManager from '../core/createInstantSearchManager'; -import { isMetadataEnabled, injectMetadata } from '../core/metadata'; - -import type { InstantSearchContext, IndexContext } from '../core/context'; -import type { ConnectorDescription } from '../core/createConnector'; -import type { Store } from '../core/createStore'; -import type { WidgetsManager } from '../core/createWidgetsManager'; -import type { MultiResponse } from '../types/algoliasearch'; -import type { - PlainSearchParameters, - SearchParameters, -} from 'algoliasearch-helper'; - -type ResultsState = { - metadata: never[]; - state: PlainSearchParameters; - rawResults: MultiResponse; -}; - -// @TODO: move to createInstantSearchManager when it's TS -type InstantSearchManager = { - store: Store; - widgetsManager: WidgetsManager; - getWidgetsIds: () => any; - getSearchParameters: (...args: any[]) => { - mainParameters: SearchParameters; - derivedParameters: SearchParameters; - }; - onSearchForFacetValues: (...args: any[]) => any; - onExternalStateUpdate: (...args: any[]) => any; - transitionState: any; - updateClient: any; - updateIndex: any; - clearCache: () => void; - skipSearch: (...args: any[]) => any; -}; - -export type SearchClient = { - search: (requests: Array<{}>) => Promise<{}>; - searchForFacetValues: (requests: Array<{}>) => Promise<{}>; -}; - -type SearchState = any; - -type Props = { - refresh: boolean; - indexName: string; - searchClient: SearchClient; - createURL?: (searchState: SearchState, knownKeys: any) => string; - onSearchStateChange?: (searchState: SearchState) => void; - searchState?: SearchState; - onSearchParameters?: ( - getSearchParameters: ConnectorDescription['getSearchParameters'], - context: { ais: InstantSearchContext; multiIndexContext: IndexContext }, - props: object, - searchState: SearchState - ) => void; - widgetsCollector?: (args: { - getSearchParameters: ConnectorDescription['getSearchParameters']; - getMetadata: ConnectorDescription['getMetadata']; - searchState: SearchState; - context: { ais: InstantSearchContext; multiIndexContext: IndexContext }; - props: object; - displayName: string; - }) => void; - stalledSearchDelay?: number; - resultsState?: ResultsState | { [indexId: string]: ResultsState }; - children?: React.ReactNode; -}; - -type State = { - isControlled: boolean; - instantSearchManager: InstantSearchManager; - contextValue: InstantSearchContext; -}; - -function isControlled(props: Props) { - return Boolean(props.searchState); -} - -/** - * @description - * `` is the root component of all React InstantSearch implementations. - * It provides all the connected components (aka widgets) a means to interact - * with the searchState. - * @kind widget - * @name - * @requirements You will need to have an Algolia account to be able to use this widget. - * [Create one now](https://www.algolia.com/users/sign_up). - * @propType {string} indexName - Main index in which to search. - * @propType {boolean} [refresh=false] - Flag to activate when the cache needs to be cleared so that the front-end is updated when a change occurs in the index. - * @propType {object} [searchClient] - Provide a custom search client. - * @propType {func} [onSearchStateChange] - Function to be called everytime a new search is done. Useful for [URL Routing](guide/Routing.html). - * @propType {object} [searchState] - Object to inject some search state. Switches the InstantSearch component in controlled mode. Useful for [URL Routing](guide/Routing.html). - * @propType {func} [createURL] - Function to call when creating links, useful for [URL Routing](guide/Routing.html). - * @propType {SearchResults|SearchResults[]} [resultsState] - Use this to inject the results that will be used at first rendering. Those results are found by using the `findResultsState` function. Useful for [Server Side Rendering](guide/Server-side_rendering.html). - * @propType {number} [stalledSearchDelay=200] - The amount of time before considering that the search takes too much time. The time is expressed in milliseconds. - * @propType {{ Root: string|function, props: object }} [root] - Use this to customize the root element. Default value: `{ Root: 'div' }` - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ -class InstantSearch extends Component { - static defaultProps = { - stalledSearchDelay: 200, - refresh: false, - }; - - static propTypes = { - // @TODO: These props are currently constant. - indexName: PropTypes.string.isRequired, - - searchClient: PropTypes.shape({ - search: PropTypes.func.isRequired, - searchForFacetValues: PropTypes.func, - addAlgoliaAgent: PropTypes.func, - clearCache: PropTypes.func, - }).isRequired, - - createURL: PropTypes.func, - - refresh: PropTypes.bool, - - searchState: PropTypes.object, - onSearchStateChange: PropTypes.func, - - onSearchParameters: PropTypes.func, - widgetsCollector: PropTypes.func, - resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]), - - children: PropTypes.node, - stalledSearchDelay: PropTypes.number, - }; - - static getDerivedStateFromProps( - nextProps: Props, - prevState: State - ): Partial { - const nextIsControlled = isControlled(nextProps); - const previousSearchState = - prevState.instantSearchManager.store.getState().widgets; - const nextSearchState = nextProps.searchState; - - if (nextIsControlled && !isEqual(previousSearchState, nextSearchState)) { - prevState.instantSearchManager.onExternalStateUpdate( - nextProps.searchState - ); - } - - return { - isControlled: nextIsControlled, - contextValue: { - ...prevState.contextValue, - mainTargetedIndex: nextProps.indexName, - }, - }; - } - - cleanupTimerRef: ReturnType | null = null; - isUnmounting: boolean = false; - - constructor(props: Props) { - super(props); - - const instantSearchManager = createInstantSearchManager({ - indexName: this.props.indexName, - searchClient: this.props.searchClient, - initialState: this.props.searchState || {}, - resultsState: this.props.resultsState, - stalledSearchDelay: this.props.stalledSearchDelay, - }); - - const contextValue = { - store: instantSearchManager.store, - widgetsManager: instantSearchManager.widgetsManager, - mainTargetedIndex: this.props.indexName, - onInternalStateUpdate: this.onWidgetsInternalStateUpdate.bind(this), - createHrefForState: this.createHrefForState.bind(this), - onSearchForFacetValues: this.onSearchForFacetValues.bind(this), - onSearchStateChange: this.onSearchStateChange.bind(this), - onSearchParameters: this.onSearchParameters.bind(this), - }; - - this.state = { - isControlled: isControlled(this.props), - instantSearchManager, - contextValue, - }; - } - - componentDidUpdate(prevProps: Props) { - const prevIsControlled = isControlled(prevProps); - - if (prevIsControlled && !this.state.isControlled) { - throw new Error( - "You can't switch from being controlled to uncontrolled" - ); - } - - if (!prevIsControlled && this.state.isControlled) { - throw new Error( - "You can't switch from being uncontrolled to controlled" - ); - } - - if (this.props.refresh !== prevProps.refresh && this.props.refresh) { - this.state.instantSearchManager.clearCache(); - } - - if (prevProps.indexName !== this.props.indexName) { - this.state.instantSearchManager.updateIndex(this.props.indexName); - } - - if (prevProps.searchClient !== this.props.searchClient) { - this.state.instantSearchManager.updateClient(this.props.searchClient); - } - } - - componentDidMount() { - if (this.cleanupTimerRef) { - clearTimeout(this.cleanupTimerRef); - this.cleanupTimerRef = null; - } - - if (isMetadataEnabled()) { - injectMetadata( - this.state.instantSearchManager.widgetsManager.getWidgets(), - this.props.searchClient - ); - } - } - - componentWillUnmount() { - this.cleanupTimerRef = setTimeout(() => { - this.isUnmounting = true; - this.state.instantSearchManager.skipSearch(); - }); - } - - createHrefForState(searchState: SearchState) { - searchState = this.state.instantSearchManager.transitionState(searchState); - return this.state.isControlled && this.props.createURL - ? this.props.createURL(searchState, this.getKnownKeys()) - : '#'; - } - - onWidgetsInternalStateUpdate(searchState: SearchState) { - searchState = this.state.instantSearchManager.transitionState(searchState); - - this.onSearchStateChange(searchState); - - if (!this.state.isControlled) { - this.state.instantSearchManager.onExternalStateUpdate(searchState); - } - } - - onSearchStateChange(searchState: any) { - if (this.props.onSearchStateChange && !this.isUnmounting) { - this.props.onSearchStateChange(searchState); - } - } - - onSearchParameters( - getSearchParameters: ConnectorDescription['getMetadata'], - context: { - ais: InstantSearchContext; - multiIndexContext: IndexContext; - }, - props: object, - getMetadata: ConnectorDescription['getMetadata'], - displayName: string - ) { - if (this.props.onSearchParameters) { - const searchState = this.props.searchState ? this.props.searchState : {}; - this.props.onSearchParameters( - getSearchParameters, - context, - props, - searchState - ); - } - if (this.props.widgetsCollector) { - const searchState = this.props.searchState ? this.props.searchState : {}; - this.props.widgetsCollector({ - getSearchParameters, - getMetadata, - context, - props, - searchState, - displayName, - }); - } - } - - onSearchForFacetValues(searchState: any) { - this.state.instantSearchManager.onSearchForFacetValues(searchState); - } - - getKnownKeys() { - return this.state.instantSearchManager.getWidgetsIds(); - } - - render() { - if (Children.count(this.props.children) === 0) { - return null; - } - - return ( - - {this.props.children} - - ); - } -} - -export default InstantSearch; diff --git a/packages/react-instantsearch-core/src/widgets/QueryRuleContext.ts b/packages/react-instantsearch-core/src/widgets/QueryRuleContext.ts deleted file mode 100644 index ad9578ead2..0000000000 --- a/packages/react-instantsearch-core/src/widgets/QueryRuleContext.ts +++ /dev/null @@ -1,8 +0,0 @@ -import connectQueryRules from '../connectors/connectQueryRules'; - -export default connectQueryRules( - function QueryRuleContext() { - return null; - }, - { $$widgetType: 'ais.queryRuleContext' } -); diff --git a/packages/react-instantsearch-core/src/widgets/__tests__/DynamicWidgets.test.tsx b/packages/react-instantsearch-core/src/widgets/__tests__/DynamicWidgets.test.tsx deleted file mode 100644 index 4ee0cd7565..0000000000 --- a/packages/react-instantsearch-core/src/widgets/__tests__/DynamicWidgets.test.tsx +++ /dev/null @@ -1,439 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { render } from '@testing-library/react'; -import React from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; -import { Panel } from 'react-instantsearch-dom'; - -import { - connectHierarchicalMenu, - connectMenu, - connectPagination, - connectRefinementList, -} from '../..'; -import DynamicWidgets from '../DynamicWidgets'; -import InstantSearch from '../InstantSearch'; - -const EMPTY_RESPONSE = { - results: [ - { - hits: [], - nbHits: 0, - page: 0, - nbPages: 0, - hitsPerPage: 20, - exhaustiveNbHits: true, - query: '', - queryAfterRemoval: '', - params: - 'highlightPreTag=%3Cais-highlight-0000000000%3E&highlightPostTag=%3C%2Fais-highlight-0000000000%3E&query=&facets=%5B%5D&tagFilters=', - index: 'instant_search', - processingTimeMS: 2, - }, - ], -}; - -const createSearchClient = () => ({ - search: jest.fn(() => Promise.resolve(EMPTY_RESPONSE)), - searchForFacetValues: jest.fn(() => Promise.resolve({})), -}); - -const RefinementList = connectRefinementList( - ({ attribute }: { attribute: string }) => `RefinementList(${attribute})` -); - -const HierarchicalMenu = connectHierarchicalMenu( - ({ attributes }: { attributes: string[] }) => - `HierarchicalMenu([${attributes.join(', ')}])` -); - -const Menu = connectMenu( - ({ attribute, otherProp }: { attribute: string; otherProp: any }) => - `Menu(${attribute})${otherProp ? ` ${JSON.stringify({ otherProp })}` : ''}` -); - -const Pagination = connectPagination(() => { - return
pagination
; -}); - -describe('DynamicWidgets', () => { - describe('before results', () => { - test('does not render the result of transformItems', () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1']}> - - - - ); - - expect(container).toMatchInlineSnapshot(`
`); - }); - }); - - describe('with results', () => { - const resultsState = { - metadata: [], - rawResults: EMPTY_RESPONSE.results, - state: { - index: 'instant_search', - query: '', - }, - }; - - test('default items is empty', () => { - const searchClient = createSearchClient(); - - const { container } = render( - - items}> - - - - ); - - expect(container).toMatchInlineSnapshot(`
`); - }); - - test('renders return of transformItems', () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1']}> - - - - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) -
- `); - }); - - test('renders from results', () => { - const searchClient = createSearchClient(); - - const RESULTS = [ - { - ...resultsState, - rawResults: [ - { - ...resultsState.rawResults[0], - renderingContent: { - facetOrdering: { facets: { order: ['test1', 'test2'] } }, - }, - }, - ], - }, - - { - ...resultsState, - rawResults: [ - { - ...resultsState.rawResults[0], - renderingContent: { - facetOrdering: { facets: { order: ['test2', 'test1'] } }, - }, - }, - ], - }, - - { - ...resultsState, - rawResults: [ - { - ...resultsState.rawResults[0], - renderingContent: { - facetOrdering: { facets: { order: ['test1'] } }, - }, - }, - ], - }, - ]; - - const Component = ({ - result, - }: { - result: React.ComponentProps['resultsState']; - }) => ( - - - - - - - ); - { - const { container } = render( - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) - HierarchicalMenu([test2, test3]) -
- `); - } - { - const { container } = render( - - ); - - expect(container).toMatchInlineSnapshot(` -
- HierarchicalMenu([test2, test3]) - RefinementList(test1) -
- `); - } - { - const { container } = render( - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) -
- `); - } - }); - - test('renders items in panel', () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1', 'test3', 'test5']}> - - - - - - - - - - - - - - - - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) -
-
- RefinementList(test3) -
-
-
-
- HierarchicalMenu([test5, test5.1]) -
-
-
- `); - }); - - test("does not render items that aren't directly in children", () => { - const fallbackRender = jest.fn(() => null); - - // prevent duplicate console errors still showing up - const spy = jest.spyOn(console, 'error'); - spy.mockImplementation(() => {}); - - const searchClient = createSearchClient(); - - const Wrapped = ({ attr }: { attr: string }) => ( -
- -
- ); - - render( - - - ['test1']}> - - - - - ); - - // note: this test now expects a failure, but if we ever implement deep - // fetching of attribute, we expect this to render Wrapped - expect( - (fallbackRender.mock.calls[0] as any)[0].error - ).toMatchInlineSnapshot( - `[Error: Could not find "attribute" prop for UnknownComponent.]` - ); - }); - - test('does not render items non-attribute widgets', () => { - const fallbackRender = jest.fn(() => null); - - // prevent duplicate console errors still showing up - const spy = jest.spyOn(console, 'error'); - spy.mockImplementation(() => {}); - - const searchClient = createSearchClient(); - - render( - - - ['test1']}> - - - - - ); - - expect( - (fallbackRender.mock.calls[0] as any)[0].error - ).toMatchInlineSnapshot( - `[Error: Could not find "attribute" prop for UnknownComponent.]` - ); - }); - - test('does not render attributes without widget by default', () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1', 'test2', 'test3']}> - - - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) -
- `); - }); - - test("uses fallbackComponent component to create widgets that aren't explicitly declared", () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1', 'test2', 'test3']} - fallbackComponent={Menu} - > - - - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) - Menu(test2) - Menu(test3) -
- `); - }); - - test("uses fallbackComponent callback to create widgets that aren't explicitly declared", () => { - const searchClient = createSearchClient(); - - const { container } = render( - - ['test1', 'test2', 'test3']} - fallbackComponent={({ attribute }: { attribute: string }) => ( - - )} - > - - - - ); - - expect(container).toMatchInlineSnapshot(` -
- RefinementList(test1) - Menu(test2) {"otherProp":true} - Menu(test3) {"otherProp":true} -
- `); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/widgets/__tests__/Index.js b/packages/react-instantsearch-core/src/widgets/__tests__/Index.js deleted file mode 100644 index 344ea5ab5d..0000000000 --- a/packages/react-instantsearch-core/src/widgets/__tests__/Index.js +++ /dev/null @@ -1,216 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import { SearchParameters } from 'algoliasearch-helper'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; - -import { IndexConsumer, InstantSearchProvider } from '../../core/context'; -import createConnector from '../../core/createConnector'; -import Index, { IndexComponentWithoutContext } from '../Index'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Index', () => { - const createContext = () => ({ - onSearchParameters: jest.fn(), - widgetsManager: { - registerWidget: jest.fn(), - update: jest.fn(), - }, - }); - - const requiredProps = { - indexName: 'indexName', - indexId: 'indexId', - root: { - Root: 'div', - }, - }; - - it('registers itself on mount', () => { - const context = createContext(); - - const wrapper = shallow( - -
- - ); - - expect(context.widgetsManager.registerWidget).toHaveBeenCalledTimes(1); - expect(context.widgetsManager.registerWidget).toHaveBeenCalledWith( - wrapper.instance() - ); - }); - - it('calls onSearchParameters on mount', () => { - const context = createContext(); - - shallow( - -
- - ); - - expect(context.onSearchParameters).toHaveBeenCalledTimes(1); - }); - - it('calls update if indexName prop changes', () => { - const context = createContext(); - - // componentDidUpdate wasn't called on `shallow` - const wrapper = mount( - -
- - ); - - expect(context.widgetsManager.update).toHaveBeenCalledTimes(0); - - wrapper.setProps({ indexName: 'newIndexName' }); - - expect(context.widgetsManager.update).toHaveBeenCalledTimes(1); - }); - - it('unregisters itself on unmount', () => { - const unregister = jest.fn(); - const context = createContext(); - - context.widgetsManager.registerWidget.mockImplementation(() => unregister); - - const wrapper = shallow( - -
- - ); - - expect(unregister).toHaveBeenCalledTimes(0); - - wrapper.unmount(); - - expect(unregister).toHaveBeenCalledTimes(1); - }); - - it('exposes multi index context', () => { - const context = createContext(); - - const wrapper = mount( - - - {(multiIndexContext) => ( -
{multiIndexContext.targetedIndex}
- )} -
-
- ); - - expect(wrapper.find('.inner').text()).toBe('indexId'); - }); - - it('provides search parameters from instance props', () => { - const context = createContext(); - - const wrapper = shallow( - -
- - ); - - const parameters = wrapper - .instance() - .getSearchParameters(new SearchParameters()); - - expect(parameters.index).toBe('indexName'); - }); - - it('provides search parameters from argument props when instance props are not available', () => { - const context = createContext(); - - const wrapper = shallow( - -
- - ); - - const parameters = wrapper - .instance() - .getSearchParameters.call({}, new SearchParameters(), { - indexName: 'otherIndexName', - }); - - expect(parameters.index).toBe('otherIndexName'); - }); - - it('wrapped with InstantSearchProvider: sets correct props', () => { - const state = { - results: {}, - resultsFacetValues: {}, - searching: false, - searchingForFacetValues: false, - isSearchStalled: false, - metadata: {}, - error: {}, - widgets: { - query: 'hello', - }, - }; - - const context = { - onInternalStateUpdate() {}, - createHrefForState() {}, - onSearchForFacetValues() {}, - onSearchStateChange() {}, - onSearchParameters() {}, - widgetsManager: { - registerWidget() {}, - getWidgets() {}, - update() {}, - }, - store: { - setState() {}, - subscribe() {}, - getState: () => state, - }, - }; - - const Dummy = (props) => JSON.stringify(props, null, 2).replace(/"/g, ''); - - const Connected = createConnector({ - displayName: 'Connector', - getProvidedProps: (props) => ({ providedProps: props }), - })(Dummy); - - const props = { - message: 'hello', - }; - - const wrapper = mount( - - - - - - ); - - expect(wrapper.text()).toMatchInlineSnapshot(` -"{ - indexContextValue: { - targetedIndex: indexId - }, - message: hello, - providedProps: { - contextValue: { - widgetsManager: {}, - store: {} - }, - indexContextValue: { - targetedIndex: indexId - }, - message: hello - } -}" -`); - }); -}); diff --git a/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.integration.js b/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.integration.js deleted file mode 100644 index ce7aa4b47a..0000000000 --- a/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.integration.js +++ /dev/null @@ -1,187 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { createAlgoliaSearchClient } from '@instantsearch/mocks'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import algoliasearch from 'algoliasearch'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; - -import { connectHits, connectRefinementList, Index } from '../../index'; -import InstantSearch from '../InstantSearch'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('metadata', () => { - const defaultUserAgent = - 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1 Safari/605.1.15'; - const algoliaUserAgent = 'Algolia Crawler 5.3.2'; - - Object.defineProperty( - window.navigator, - 'userAgent', - ((value) => ({ - get() { - return value; - }, - set(v) { - value = v; - }, - }))(window.navigator.userAgent) - ); - - afterEach(() => { - navigator.userAgent = defaultUserAgent; - document.head.innerHTML = ''; - }); - - test('adds no metadata to if not on crawler', () => { - const RefinementList = connectRefinementList(() => null); - const Hits = connectHits(() => null); - - mount( - - - - - - - ); - - expect(document.head).toMatchInlineSnapshot(``); - }); - - test('exposes widgets', () => { - navigator.userAgent = algoliaUserAgent; - - const RefinementList = connectRefinementList(() => null); - const Hits = connectHits(() => null); - - mount( - - - - - - - ); - - expect(document.head.children).toHaveLength(1); - - const meta = document.head.querySelector('meta'); - - expect(meta).toEqual( - expect.objectContaining({ - name: 'algolia:metadata', - content: expect.any(String), - }) - ); - - expect(JSON.parse(meta.content)).toMatchInlineSnapshot(` - { - "ua": "Algolia for JavaScript (test)", - "widgets": [ - { - "$$type": "ais.refinementList", - "displayName": "AlgoliaRefinementList", - "params": [ - "attribute", - ], - }, - { - "$$type": "ais.hits", - "displayName": "AlgoliaHits", - "params": [], - }, - { - "$$type": "ais.index", - "$$widgetType": "ais.index", - "displayName": "AlgoliaIndex", - "params": [ - "indexId", - "indexName", - "children", - ], - }, - ], - } - `); - }); - - describe('algoliaAgent', () => { - test('extracts user agent from algoliasearch v3', () => { - navigator.userAgent = algoliaUserAgent; - - mount( - - ); - - const meta = document.head.querySelector('meta'); - - expect(meta).toEqual( - expect.objectContaining({ - name: 'algolia:metadata', - content: expect.any(String), - }) - ); - - expect(JSON.parse(meta.content)).toMatchInlineSnapshot(` - { - "ua": "user agent v3", - "widgets": [], - } - `); - }); - - test('extracts user agent from algoliasearch', () => { - navigator.userAgent = algoliaUserAgent; - - mount( - - ); - - expect(document.head.children).toHaveLength(1); - expect(document.head.children[0]).toEqual(expect.any(HTMLMetaElement)); - - expect(JSON.parse(document.head.querySelector('meta').content)).toEqual({ - ua: expect.stringMatching( - /^Algolia for JavaScript \((\d+\.?)+\); Node\.js \((\d+\.?)+\); JS Helper \(3\.(\d+\.?)+\); react \((\d+\.?)+\); react-instantsearch \(6\.(\d+\.?)+\)$/ - ), - widgets: [], - }); - }); - - test('extracts user agent from custom client', () => { - navigator.userAgent = algoliaUserAgent; - - mount( - - ); - - expect(document.head).toMatchInlineSnapshot(` - - - - `); - }); - }); -}); diff --git a/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.js b/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.js deleted file mode 100644 index fe4405e459..0000000000 --- a/packages/react-instantsearch-core/src/widgets/__tests__/InstantSearch.js +++ /dev/null @@ -1,598 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { wait } from '@instantsearch/testutils'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; - -import { InstantSearchConsumer } from '../../core/context'; -import createInstantSearchManager from '../../core/createInstantSearchManager'; -import InstantSearch from '../InstantSearch'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('../../core/createInstantSearchManager'); - -const createFakeStore = (rest = {}) => ({ - getState: jest.fn(() => ({})), - setState: jest.fn(), - subscribe: jest.fn(), - ...rest, -}); - -const createFakeInstantSearchManager = (rest = {}) => ({ - context: {}, - store: createFakeStore(), - clearCache: jest.fn(), - updateIndex: jest.fn(), - updateClient: jest.fn(), - skipSearch: jest.fn(), - getWidgetsIds: jest.fn(), - onExternalStateUpdate: jest.fn(), - onSearchForFacetValues: jest.fn(), - transitionState: jest.fn(), - ...rest, -}); - -const createFakeSearchClient = (rest = {}) => ({ - search: jest.fn(), - ...rest, -}); - -const DEFAULT_PROPS = { - appId: 'foo', - apiKey: 'bar', - indexName: 'foobar', - searchClient: createFakeSearchClient(), - root: { - Root: 'div', - }, - refresh: false, -}; - -describe('InstantSearch', () => { - beforeEach(() => { - createInstantSearchManager.mockImplementation(() => - createFakeInstantSearchManager() - ); - }); - - afterEach(() => { - createInstantSearchManager.mockClear(); - }); - - it('validates its props', () => { - expect(() => { - shallow( - -
- - ); - }).not.toThrow(); - - expect(() => { - shallow(); - }).not.toThrow(); - - expect(() => { - shallow( - -
-
- - ); - }).not.toThrow(); - - expect(() => { - const wrapper = shallow( - null} - createURL={() => null} - refresh={false} - > -
- - ); - wrapper.setProps({ - searchState: undefined, - }); - }).toThrow( - "You can't switch from being controlled to uncontrolled" - ); - - expect(() => { - const wrapper = shallow( - -
- - ); - wrapper.setProps({ - searchState: {}, - onSearchStateChange: () => null, - createURL: () => null, - }); - }).toThrow( - "You can't switch from being uncontrolled to controlled" - ); - - expect(() => { - const wrapper = shallow( - null} - createURL={() => null} - > -
- - ); - wrapper.setProps({ - searchState: undefined, - onSearchStateChange: undefined, - createURL: undefined, - }); - }).toThrow( - "You can't switch from being controlled to uncontrolled" - ); - }); - - it('correctly instantiates the isManager', () => { - mount( - -
- - ); - expect(createInstantSearchManager.mock.calls[0][0]).toEqual({ - indexName: DEFAULT_PROPS.indexName, - initialState: {}, - searchClient: DEFAULT_PROPS.searchClient, - stalledSearchDelay: 200, - }); - }); - - it('updates Algolia client when new one is given in props', () => { - const ism = createFakeInstantSearchManager(); - - createInstantSearchManager.mockImplementation(() => ism); - - const wrapper = mount( - -
- - ); - - expect(ism.updateClient).toHaveBeenCalledTimes(0); - - wrapper.setProps({ - ...DEFAULT_PROPS, - searchClient: createFakeSearchClient(), - }); - - expect(ism.updateClient).toHaveBeenCalledTimes(1); - }); - - it('works as a controlled input', () => { - const ism = createFakeInstantSearchManager({ - transitionState: (searchState) => ({ - ...searchState, - transitioned: true, - }), - }); - createInstantSearchManager.mockImplementation(() => ism); - const initialState = { a: 0 }; - const onSearchStateChange = jest.fn((searchState) => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - wrapper.setProps({ - searchState: { a: searchState.a + 1 }, - }); - }); - const wrapper = mount( - '#'} - > - - {(contextValue) => ( - - )} -
-); - -Control.propTypes = { - ...ControlPropTypes, - isRefineOnMapMove: PropTypes.bool.isRequired, - toggleRefineOnMapMove: PropTypes.func.isRequired, - hasMapMoveSinceLastRefine: PropTypes.bool.isRequired, - refineWithInstance: PropTypes.func.isRequired, -}; - -const ControlWrapper = (props) => ( - - {({ - isRefineOnMapMove, - hasMapMoveSinceLastRefine, - toggleRefineOnMapMove, - refineWithInstance, - }) => ( - - )} - -); - -ControlWrapper.propTypes = ControlPropTypes; - -export default translatable({ - control: 'Search as I move the map', - redo: 'Redo search here', -})(withGoogleMaps(ControlWrapper)); diff --git a/packages/react-instantsearch-dom-maps/src/CustomMarker.js b/packages/react-instantsearch-dom-maps/src/CustomMarker.js deleted file mode 100644 index b891131e11..0000000000 --- a/packages/react-instantsearch-dom-maps/src/CustomMarker.js +++ /dev/null @@ -1,112 +0,0 @@ -import PropTypes from 'prop-types'; -import { Component } from 'react'; -import ReactDOM from 'react-dom'; - -import createHTMLMarker from './elements/createHTMLMarker'; -import { GeolocHitPropType } from './propTypes'; -import { registerEvents, createListenersPropTypes } from './utils'; -import withGoogleMaps from './withGoogleMaps'; - -const eventTypes = { - onClick: 'click', - onDoubleClick: 'dblclick', - onMouseDown: 'mousedown', - onMouseEnter: 'mouseenter', - onMouseLeave: 'mouseleave', - onMouseMove: 'mousemove', - onMouseOut: 'mouseout', - onMouseOver: 'mouseover', - onMouseUp: 'mouseup', -}; - -export class CustomMarker extends Component { - static propTypes = { - ...createListenersPropTypes(eventTypes), - hit: GeolocHitPropType.isRequired, - children: PropTypes.node.isRequired, - google: PropTypes.object.isRequired, - googleMapsInstance: PropTypes.object.isRequired, - className: PropTypes.string, - anchor: PropTypes.shape({ - x: PropTypes.number.isRequired, - y: PropTypes.number.isRequired, - }), - }; - - static defaultProps = { - className: '', - anchor: { - x: 0, - y: 0, - }, - }; - - static isReact16() { - return typeof ReactDOM.createPortal === 'function'; - } - - state = { - marker: null, - }; - - componentDidMount() { - const { hit, google, googleMapsInstance, className, anchor } = this.props; - // Not the best way to create the reference of the CustomMarker - // but since the Google object is required didn't find another - // solution. Ideas? - const Marker = createHTMLMarker(google); - - const marker = new Marker({ - map: googleMapsInstance, - position: hit._geoloc, - className, - anchor, - }); - - this.removeListeners = registerEvents(eventTypes, this.props, marker); - - this.setState(() => ({ - marker, - })); - } - - componentDidUpdate() { - const { children } = this.props; - const { marker } = this.state; - - this.removeListeners(); - - this.removeListeners = registerEvents(eventTypes, this.props, marker); - - if (!CustomMarker.isReact16()) { - ReactDOM.unstable_renderSubtreeIntoContainer( - this, - children, - marker.element - ); - } - } - - componentWillUnmount() { - const { marker } = this.state; - - if (!CustomMarker.isReact16()) { - ReactDOM.unmountComponentAtNode(marker.element); - } - - marker.setMap(null); - } - - render() { - const { children } = this.props; - const { marker } = this.state; - - if (!marker || !CustomMarker.isReact16()) { - return null; - } - - return ReactDOM.createPortal(children, marker.element); - } -} - -export default withGoogleMaps(CustomMarker); diff --git a/packages/react-instantsearch-dom-maps/src/GeoSearch.js b/packages/react-instantsearch-dom-maps/src/GeoSearch.js deleted file mode 100644 index eae2918898..0000000000 --- a/packages/react-instantsearch-dom-maps/src/GeoSearch.js +++ /dev/null @@ -1,90 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import Connector from './Connector'; -import GoogleMaps from './GoogleMaps'; -import { LatLngPropType, BoundingBoxPropType } from './propTypes'; -import Provider from './Provider'; - -class GeoSearch extends Component { - static propTypes = { - google: PropTypes.object.isRequired, - children: PropTypes.func.isRequired, - initialZoom: PropTypes.number, - initialPosition: LatLngPropType, - enableRefine: PropTypes.bool, - enableRefineOnMapMove: PropTypes.bool, - defaultRefinement: BoundingBoxPropType, - }; - - static defaultProps = { - initialZoom: 1, - initialPosition: { lat: 0, lng: 0 }, - enableRefine: true, - enableRefineOnMapMove: true, - defaultRefinement: null, - }; - - renderChildrenWithBoundFunction = ({ hits, position, ...rest }) => { - const { - google, - children, - initialZoom, - initialPosition, - enableRefine, - enableRefineOnMapMove, - defaultRefinement, - ...mapOptions - } = this.props; - - return ( - - {({ - boundingBox, - boundingBoxPadding, - onChange, - onIdle, - shouldUpdate, - }) => ( - - {children({ hits })} - - )} - - ); - }; - - render() { - const { enableRefineOnMapMove, defaultRefinement } = this.props; - - return ( - - {this.renderChildrenWithBoundFunction} - - ); - } -} - -export default GeoSearch; diff --git a/packages/react-instantsearch-dom-maps/src/GeoSearchContext.ts b/packages/react-instantsearch-dom-maps/src/GeoSearchContext.ts deleted file mode 100644 index 6161da51ab..0000000000 --- a/packages/react-instantsearch-dom-maps/src/GeoSearchContext.ts +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react'; - -type GeoSearchContextState = { - isRefineOnMapMove: boolean; - hasMapMoveSinceLastRefine: boolean; - toggleRefineOnMapMove: () => void; - setMapMoveSinceLastRefine: (value: boolean) => void; - refineWithInstance: (value: google.maps.Map) => void; -}; - -const GeoSearchContext = React.createContext({ - // The actual default value comes from the prop of the component - // wrapping the `Provider`. - isRefineOnMapMove: true, - hasMapMoveSinceLastRefine: false, - toggleRefineOnMapMove: () => {}, - setMapMoveSinceLastRefine: () => {}, - refineWithInstance: () => {}, -}); - -export default GeoSearchContext; diff --git a/packages/react-instantsearch-dom-maps/src/GoogleMaps.js b/packages/react-instantsearch-dom-maps/src/GoogleMaps.js deleted file mode 100644 index bf3ed386cd..0000000000 --- a/packages/react-instantsearch-dom-maps/src/GoogleMaps.js +++ /dev/null @@ -1,155 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component, createRef } from 'react'; -import { createClassNames } from 'react-instantsearch-dom'; - -import GoogleMapsContext from './GoogleMapsContext'; -import { LatLngPropType, BoundingBoxPropType } from './propTypes'; - -const cx = createClassNames('GeoSearch'); - -class GoogleMaps extends Component { - static propTypes = { - google: PropTypes.object.isRequired, - initialZoom: PropTypes.number.isRequired, - initialPosition: LatLngPropType.isRequired, - mapOptions: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - onIdle: PropTypes.func.isRequired, - shouldUpdate: PropTypes.func.isRequired, - boundingBox: BoundingBoxPropType, - boundingBoxPadding: PropTypes.number, - children: PropTypes.node, - }; - - isUserInteraction = true; - isPendingRefine = false; - listeners = []; - mapRef = createRef(); - - state = { - isMapReady: false, - }; - - componentDidMount() { - const { google, mapOptions } = this.props; - - this.instance = new google.maps.Map(this.mapRef.current, { - mapTypeControl: false, - fullscreenControl: false, - streetViewControl: false, - clickableIcons: false, - zoomControlOptions: { - position: google.maps.ControlPosition.LEFT_TOP, - }, - ...mapOptions, - }); - - this.listeners.push( - google.maps.event.addListenerOnce( - this.instance, - 'idle', - this.setupListenersWhenMapIsReady - ) - ); - } - - componentDidUpdate() { - const { - google, - initialZoom, - initialPosition, - boundingBox, - boundingBoxPadding, - shouldUpdate, - } = this.props; - - if (!shouldUpdate()) { - return; - } - - if (boundingBox) { - this.lockUserInteraction(() => { - const oldBounds = this.instance.getBounds(); - - // south west and north east are swapped - const newBounds = new google.maps.LatLngBounds( - boundingBox.southWest, - boundingBox.northEast - ); - - if (!newBounds.equals(oldBounds)) { - this.instance.fitBounds(newBounds, boundingBoxPadding); - } - }); - } else { - this.lockUserInteraction(() => { - this.instance.setZoom(initialZoom); - this.instance.setCenter(initialPosition); - }); - } - } - - componentWillUnmount() { - this.listeners.forEach((listener) => { - listener.remove(); - }); - - this.listeners = []; - } - - setupListenersWhenMapIsReady = () => { - this.listeners = []; - - this.setState({ - isMapReady: true, - value: { - google: this.props.google, - instance: this.instance, - }, - }); - - const onChange = () => { - if (this.isUserInteraction) { - this.props.onChange(); - } - }; - - this.listeners.push(this.instance.addListener('center_changed', onChange)); - this.listeners.push(this.instance.addListener('zoom_changed', onChange)); - this.listeners.push(this.instance.addListener('dragstart', onChange)); - - this.listeners.push( - this.instance.addListener('idle', () => { - if (this.isUserInteraction) { - this.props.onIdle({ - instance: this.instance, - }); - } - }) - ); - }; - - lockUserInteraction(functionThatAltersTheMapPosition) { - this.isUserInteraction = false; - functionThatAltersTheMapPosition(); - this.isUserInteraction = true; - } - - render() { - const { children } = this.props; - const { isMapReady } = this.state; - - return ( -
-
- {isMapReady && ( - - {children} - - )} -
- ); - } -} - -export default GoogleMaps; diff --git a/packages/react-instantsearch-dom-maps/src/GoogleMapsContext.ts b/packages/react-instantsearch-dom-maps/src/GoogleMapsContext.ts deleted file mode 100644 index 0093341562..0000000000 --- a/packages/react-instantsearch-dom-maps/src/GoogleMapsContext.ts +++ /dev/null @@ -1,16 +0,0 @@ -import React from 'react'; - -export type GoogleMapsContextState = { - google: typeof google; - instance: google.maps.Map; -}; - -const GoogleMapsContext = React.createContext({ - // We mount the context only once the map is created. Thus, we can assume - // that the value provided through the context is never `undefined`. We can't - // create an instance at that point, hence the cast. - google: {} as unknown as typeof google, - instance: {} as unknown as google.maps.Map, -}); - -export default GoogleMapsContext; diff --git a/packages/react-instantsearch-dom-maps/src/GoogleMapsLoader.js b/packages/react-instantsearch-dom-maps/src/GoogleMapsLoader.js deleted file mode 100644 index 2766ae2cdf..0000000000 --- a/packages/react-instantsearch-dom-maps/src/GoogleMapsLoader.js +++ /dev/null @@ -1,53 +0,0 @@ -import PropTypes from 'prop-types'; -import { Component } from 'react'; - -class GoogleMapsLoader extends Component { - static propTypes = { - apiKey: PropTypes.string.isRequired, - children: PropTypes.func.isRequired, - endpoint: PropTypes.string, - }; - - static defaultProps = { - endpoint: 'https://maps.googleapis.com/maps/api/js?v=quarterly', - }; - - state = { - google: null, - }; - - isUnmounting = false; - - componentDidMount() { - // Inline the import to avoid to run the module on the server (rely on `document`) - // Under the hood we use `dynamic-import-node` to transpile the `import` to `require` - // see: https://github.com/algolia/react-instantsearch/issues/1425 - return import('scriptjs').then(({ default: injectScript }) => { - const { apiKey, endpoint } = this.props; - const operator = endpoint.indexOf('?') !== -1 ? '&' : '?'; - const endpointWithCredentials = `${endpoint}${operator}key=${apiKey}`; - - injectScript(endpointWithCredentials, () => { - if (!this.isUnmounting) { - this.setState(() => ({ - google: window.google, - })); - } - }); - }); - } - - componentWillUnmount() { - this.isUnmounting = true; - } - - render() { - if (!this.state.google) { - return null; - } - - return this.props.children(this.state.google); - } -} - -export default GoogleMapsLoader; diff --git a/packages/react-instantsearch-dom-maps/src/Marker.js b/packages/react-instantsearch-dom-maps/src/Marker.js deleted file mode 100644 index ff9e8ed25a..0000000000 --- a/packages/react-instantsearch-dom-maps/src/Marker.js +++ /dev/null @@ -1,67 +0,0 @@ -import PropTypes from 'prop-types'; -import { Component } from 'react'; - -import { GeolocHitPropType } from './propTypes'; -import { - registerEvents, - createListenersPropTypes, - createFilterProps, -} from './utils'; -import withGoogleMaps from './withGoogleMaps'; - -const eventTypes = { - onClick: 'click', - onDoubleClick: 'dblclick', - onMouseDown: 'mousedown', - onMouseOut: 'mouseout', - onMouseOver: 'mouseover', - onMouseUp: 'mouseup', -}; - -const excludes = ['children'].concat(Object.keys(eventTypes)); -const filterProps = createFilterProps(excludes); - -export class Marker extends Component { - static propTypes = { - ...createListenersPropTypes(eventTypes), - google: PropTypes.object.isRequired, - googleMapsInstance: PropTypes.object.isRequired, - hit: GeolocHitPropType.isRequired, - }; - - componentDidMount() { - const { google, googleMapsInstance, hit, ...props } = this.props; - - this.instance = new google.maps.Marker({ - ...filterProps(props), - map: googleMapsInstance, - position: hit._geoloc, - }); - - this.removeEventsListeners = registerEvents( - eventTypes, - this.props, - this.instance - ); - } - - componentDidUpdate() { - this.removeEventsListeners(); - - this.removeEventsListeners = registerEvents( - eventTypes, - this.props, - this.instance - ); - } - - componentWillUnmount() { - this.instance.setMap(null); - } - - render() { - return null; - } -} - -export default withGoogleMaps(Marker); diff --git a/packages/react-instantsearch-dom-maps/src/Provider.js b/packages/react-instantsearch-dom-maps/src/Provider.js deleted file mode 100644 index c752205aee..0000000000 --- a/packages/react-instantsearch-dom-maps/src/Provider.js +++ /dev/null @@ -1,131 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import GeoSearchContext from './GeoSearchContext'; -import { LatLngPropType, BoundingBoxPropType } from './propTypes'; - -class Provider extends Component { - static propTypes = { - google: PropTypes.object.isRequired, - hits: PropTypes.arrayOf(PropTypes.object).isRequired, - isRefineOnMapMove: PropTypes.bool.isRequired, - hasMapMoveSinceLastRefine: PropTypes.bool.isRequired, - isRefineEnable: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - toggleRefineOnMapMove: PropTypes.func.isRequired, - setMapMoveSinceLastRefine: PropTypes.func.isRequired, - children: PropTypes.func.isRequired, - position: LatLngPropType, - currentRefinement: BoundingBoxPropType, - }; - - isPendingRefine = false; - boundingBox = null; - previousBoundingBox = null; - - refineWithInstance = (instance) => { - const { refine } = this.props; - - const bounds = instance.getBounds(); - - refine({ - northEast: bounds.getNorthEast().toJSON(), - southWest: bounds.getSouthWest().toJSON(), - }); - }; - - mapValue = { - isRefineOnMapMove: this.props.isRefineOnMapMove, - hasMapMoveSinceLastRefine: this.props.hasMapMoveSinceLastRefine, - toggleRefineOnMapMove: this.props.toggleRefineOnMapMove, - setMapMoveSinceLastRefine: this.props.setMapMoveSinceLastRefine, - refineWithInstance: this.refineWithInstance, - }; - - getMapValue = () => { - const haveContextValuesChanges = - this.mapValue.isRefineOnMapMove !== this.props.isRefineOnMapMove || - this.mapValue.hasMapMoveSinceLastRefine !== - this.props.hasMapMoveSinceLastRefine; - - if (haveContextValuesChanges) { - this.mapValue = { - ...this.mapValue, - isRefineOnMapMove: this.props.isRefineOnMapMove, - hasMapMoveSinceLastRefine: this.props.hasMapMoveSinceLastRefine, - }; - } - - return this.mapValue; - }; - - createBoundingBoxFromHits(hits) { - const { google } = this.props; - - const latLngBounds = hits.reduce( - (acc, hit) => acc.extend(hit._geoloc), - new google.maps.LatLngBounds() - ); - - return { - northEast: latLngBounds.getNorthEast().toJSON(), - southWest: latLngBounds.getSouthWest().toJSON(), - }; - } - - onChange = () => { - const { isRefineOnMapMove, isRefineEnable, setMapMoveSinceLastRefine } = - this.props; - - if (isRefineEnable) { - setMapMoveSinceLastRefine(true); - - if (isRefineOnMapMove) { - this.isPendingRefine = true; - } - } - }; - - onIdle = ({ instance }) => { - if (this.isPendingRefine) { - this.isPendingRefine = false; - - this.refineWithInstance(instance); - } - }; - - shouldUpdate = () => { - const { hasMapMoveSinceLastRefine } = this.props; - - return !this.isPendingRefine && !hasMapMoveSinceLastRefine; - }; - - render() { - const { hits, currentRefinement, children } = this.props; - - // We use this value for differentiate the padding to apply during - // fitBounds. When we don't have a currenRefinement (boundingBox) - // we let GoogleMaps compute the automatic padding. But when we - // provide the currentRefinement we explicitly set the padding - // to `0` otherwise the map will decrease the zoom on each refine. - const boundingBoxPadding = !currentRefinement ? undefined : 0; - const boundingBox = - !currentRefinement && Boolean(hits.length) - ? this.createBoundingBoxFromHits(hits) - : currentRefinement; - - return ( - - {children({ - onChange: this.onChange, - onIdle: this.onIdle, - shouldUpdate: this.shouldUpdate, - boundingBox, - boundingBoxPadding, - })} - - ); - } -} - -export default Provider; diff --git a/packages/react-instantsearch-dom-maps/src/Redo.js b/packages/react-instantsearch-dom-maps/src/Redo.js deleted file mode 100644 index 5d441081dc..0000000000 --- a/packages/react-instantsearch-dom-maps/src/Redo.js +++ /dev/null @@ -1,53 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import { createClassNames, translatable } from 'react-instantsearch-dom'; - -import GeoSearchContext from './GeoSearchContext'; -import withGoogleMaps from './withGoogleMaps'; - -const cx = createClassNames('GeoSearch'); -const RedoPropTypes = { - googleMapsInstance: PropTypes.object.isRequired, - translate: PropTypes.func.isRequired, -}; - -export const Redo = ({ - googleMapsInstance, - translate, - hasMapMoveSinceLastRefine, - refineWithInstance, -}) => ( -
- -
-); - -Redo.propTypes = { - ...RedoPropTypes, - hasMapMoveSinceLastRefine: PropTypes.bool.isRequired, - refineWithInstance: PropTypes.func.isRequired, -}; - -const RedoWrapper = (props) => ( - - {({ hasMapMoveSinceLastRefine, refineWithInstance }) => ( - - )} - -); - -RedoWrapper.propTypes = RedoPropTypes; - -export default translatable({ - redo: 'Redo search here', -})(withGoogleMaps(RedoWrapper)); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/Connector.js b/packages/react-instantsearch-dom-maps/src/__tests__/Connector.js deleted file mode 100644 index c2c7663a9d..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/Connector.js +++ /dev/null @@ -1,241 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import { Connector } from '../Connector'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Connector', () => { - const defaultProps = { - hits: [], - position: null, - currentRefinement: null, - isRefinedWithMap: false, - enableRefineOnMapMove: true, - refine: () => {}, - }; - - const lastRenderArgs = (fn) => fn.mock.calls[fn.mock.calls.length - 1][0]; - - it('expect to call children with props', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - expect(children).toHaveBeenCalledTimes(1); - expect(children).toHaveBeenCalledWith({ - hits: [], - position: null, - currentRefinement: null, - isRefinedWithMap: false, - isRefineOnMapMove: true, - toggleRefineOnMapMove: expect.any(Function), - hasMapMoveSinceLastRefine: false, - setMapMoveSinceLastRefine: expect.any(Function), - refine: expect.any(Function), - }); - }); - - it('expect to call children with refine on map move disabled', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - enableRefineOnMapMove: false, - }; - - shallow({children}); - - expect(children).toHaveBeenCalledTimes(1); - expect(children).toHaveBeenCalledWith( - expect.objectContaining({ - isRefineOnMapMove: false, - }) - ); - }); - - describe('getDerivedStateFromProps', () => { - it('expect reset hasMapMoveSinceLastRefine when position change', () => { - const nextProps = { - ...defaultProps, - position: { lat: 12, lng: 14 }, - currentRefinement: null, - }; - - const state = { - hasMapMoveSinceLastRefine: true, - previousPosition: { lat: 10, lng: 12 }, - previousCurrentRefinement: null, - }; - - const actual = Connector.getDerivedStateFromProps(nextProps, state); - - const expectation = { - hasMapMoveSinceLastRefine: false, - previousPosition: { lat: 12, lng: 14 }, - previousCurrentRefinement: null, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect reset hasMapMoveSinceLastRefine when currentRefinement change', () => { - const nextProps = { - ...defaultProps, - position: null, - currentRefinement: { - northEast: { lat: 12, lng: 14 }, - southWest: { lat: 14, lng: 16 }, - }, - }; - - const state = { - hasMapMoveSinceLastRefine: true, - previousPosition: null, - previousCurrentRefinement: { - northEast: { lat: 10, lng: 12 }, - southWest: { lat: 12, lng: 14 }, - }, - }; - - const actual = Connector.getDerivedStateFromProps(nextProps, state); - - const expectation = { - hasMapMoveSinceLastRefine: false, - previousPosition: null, - previousCurrentRefinement: { - northEast: { lat: 12, lng: 14 }, - southWest: { lat: 14, lng: 16 }, - }, - }; - - expect(actual).toEqual(expectation); - }); - - it('expect to not reset hasMapMoveSinceLastRefine when nothing change', () => { - const nextProps = { - ...defaultProps, - position: { lat: 10, lng: 12 }, - currentRefinement: { - northEast: { lat: 10, lng: 12 }, - southWest: { lat: 12, lng: 14 }, - }, - }; - - const state = { - hasMapMoveSinceLastRefine: true, - previousPosition: { lat: 10, lng: 12 }, - previousCurrentRefinement: { - northEast: { lat: 10, lng: 12 }, - southWest: { lat: 12, lng: 14 }, - }, - }; - - const actual = Connector.getDerivedStateFromProps(nextProps, state); - - const expectation = { - previousPosition: { lat: 10, lng: 12 }, - previousCurrentRefinement: { - northEast: { lat: 10, lng: 12 }, - southWest: { lat: 12, lng: 14 }, - }, - }; - - expect(actual).toEqual(expectation); - }); - }); - - describe('setMapMoveSinceLastRefine', () => { - it('expect to update the state with the given value', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - const wrapper = shallow({children}); - - lastRenderArgs(children).setMapMoveSinceLastRefine(true); - - expect(wrapper.state().hasMapMoveSinceLastRefine).toBe(true); - }); - - it('expect to only update the state when the given is different', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - expect(children).toHaveBeenCalledTimes(1); - expect(children).toHaveBeenLastCalledWith( - expect.objectContaining({ - hasMapMoveSinceLastRefine: false, - }) - ); - - lastRenderArgs(children).setMapMoveSinceLastRefine(true); - - expect(children).toHaveBeenCalledTimes(2); - expect(children).toHaveBeenLastCalledWith( - expect.objectContaining({ - hasMapMoveSinceLastRefine: true, - }) - ); - - lastRenderArgs(children).setMapMoveSinceLastRefine(true); - - expect(children).toHaveBeenCalledTimes(2); - expect(children).toHaveBeenLastCalledWith( - expect.objectContaining({ - hasMapMoveSinceLastRefine: true, - }) - ); - }); - }); - - describe('toggleRefineOnMapMove', () => { - it('expect to update the state with the invert of previous value (true)', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - const wrapper = shallow({children}); - - expect(wrapper.state().isRefineOnMapMove).toBe(true); - - lastRenderArgs(children).toggleRefineOnMapMove(); - - expect(wrapper.state().isRefineOnMapMove).toBe(false); - }); - - it('expect to update the state with the invert of previous value (false)', () => { - const children = jest.fn(); - - const props = { - ...defaultProps, - }; - - const wrapper = shallow({children}); - - wrapper.setState({ - isRefineOnMapMove: false, - }); - - expect(wrapper.state().isRefineOnMapMove).toBe(false); - - lastRenderArgs(children).toggleRefineOnMapMove(); - - expect(wrapper.state().isRefineOnMapMove).toBe(true); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/Control.js b/packages/react-instantsearch-dom-maps/src/__tests__/Control.js deleted file mode 100644 index 0f64ade1b0..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/Control.js +++ /dev/null @@ -1,90 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import { createFakeMapInstance } from '../../test/mockGoogleMaps'; -import { Control } from '../Control'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Control', () => { - const defaultProps = { - googleMapsInstance: createFakeMapInstance(), - translate: (x) => x, - isRefineOnMapMove: true, - hasMapMoveSinceLastRefine: false, - toggleRefineOnMapMove: () => {}, - refineWithInstance: () => {}, - }; - - it('expect to render correctly with refine on map move', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('input').props().checked).toBe(true); - }); - - it('expect to render correctly without refine on map move', () => { - const props = { - ...defaultProps, - isRefineOnMapMove: false, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('input').props().checked).toBe(false); - }); - - it('expect to render correctly without refine on map move when the map has moved', () => { - const props = { - ...defaultProps, - isRefineOnMapMove: false, - hasMapMoveSinceLastRefine: true, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to call toggleRefineOnMapMove on input change', () => { - const props = { - ...defaultProps, - toggleRefineOnMapMove: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.toggleRefineOnMapMove).toHaveBeenCalledTimes(0); - - wrapper.find('input').simulate('change'); - - expect(props.toggleRefineOnMapMove).toHaveBeenCalledTimes(1); - }); - - it('expect to call refineWithInstance on button click', () => { - const mapInstance = createFakeMapInstance(); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - isRefineOnMapMove: false, - hasMapMoveSinceLastRefine: true, - refineWithInstance: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.refineWithInstance).toHaveBeenCalledTimes(0); - - wrapper.find('button').simulate('click'); - - expect(props.refineWithInstance).toHaveBeenCalledTimes(1); - expect(props.refineWithInstance).toHaveBeenCalledWith(mapInstance); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/CustomMarker.js b/packages/react-instantsearch-dom-maps/src/__tests__/CustomMarker.js deleted file mode 100644 index b24d0a0f87..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/CustomMarker.js +++ /dev/null @@ -1,602 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount, shallow } from 'enzyme'; -import { createSerializer } from 'enzyme-to-json'; -import React from 'react'; -import ReactDOM from 'react-dom'; - -import { - createFakeGoogleReference, - createFakeMapInstance, - createFakeHTMLMarkerInstance, -} from '../../test/mockGoogleMaps'; -import Connected, { CustomMarker } from '../CustomMarker'; -import createHTMLMarker from '../elements/createHTMLMarker'; -import GoogleMapsContext from '../GoogleMapsContext'; -import * as utils from '../utils'; - -expect.addSnapshotSerializer(createSerializer()); -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('../elements/createHTMLMarker', () => jest.fn()); - -jest.mock('../utils'); - -describe('CustomMarker', () => { - const defaultProps = { - hit: { - _geoloc: { - lat: 10, - lng: 12, - }, - }, - }; - - beforeEach(() => { - utils.registerEvents.mockClear(); - utils.registerEvents.mockReset(); - - // Register default implementation - utils.registerEvents.mockImplementation(() => jest.fn()); - }); - - describe('creation', () => { - it('expect to create the marker on didMount with default options', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow( - - This is the children. - - ); - - expect(createHTMLMarker).toHaveBeenCalledWith(google); - expect(wrapper.state('marker')).toBe(marker); - - expect(factory).toHaveBeenCalledTimes(1); - expect(factory).toHaveBeenCalledWith( - expect.objectContaining({ - map: mapInstance, - position: { - lat: 10, - lng: 12, - }, - }) - ); - }); - - it('expect to create the marker on didMount with given options', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - className: 'my-marker', - googleMapsInstance: mapInstance, - anchor: { - x: 10, - y: 10, - }, - google, - }; - - shallow( - - This is the children. - - ); - - expect(factory).toHaveBeenCalledWith( - expect.objectContaining({ - className: 'my-marker', - anchor: { - x: 10, - y: 10, - }, - }) - ); - }); - - it('expect to register the listeners on didMount', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - shallow( - - This is the children. - - ); - - expect(utils.registerEvents).toHaveBeenCalledTimes(2); // cDM + cDU - expect(utils.registerEvents).toHaveBeenCalledWith( - expect.any(Object), - expect.any(Object), - marker - ); - }); - }); - - describe('update', () => { - it('expect to remove the listeners on didUpdate', () => { - const removeEventListeners = jest.fn(); - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - utils.registerEvents.mockImplementation(() => removeEventListeners); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - shallow( - - This is the children. - - ); - - expect(removeEventListeners).toHaveBeenCalledTimes(1); - }); - - it('expect to register the listeners on didUpdate', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - shallow( - - This is the children. - - ); - - expect(utils.registerEvents).toHaveBeenCalledTimes(2); // cDM + cDU - expect(utils.registerEvents).toHaveBeenCalledWith( - expect.any(Object), - expect.any(Object), - marker - ); - }); - }); - - describe('delete', () => { - it('expect to remove the Marker on willUnmount', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow( - - This is the children. - - ); - - wrapper.unmount(); - - expect(marker.setMap).toHaveBeenCalledTimes(1); - expect(marker.setMap).toHaveBeenCalledWith(null); - }); - }); - - describe('with portal', () => { - it('expect to render correctly', () => { - const unstableRenderSubtreeIntoContainer = jest.spyOn( - ReactDOM, - 'unstable_renderSubtreeIntoContainer' - ); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - utils.registerEvents.mockImplementation(() => () => {}); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - // Use `mount` instead of `shallow` to trigger the render - // of createPortal otherwise the Snapshot is empty - const wrapper = mount( - - This is the children. - - ); - - expect(wrapper).toMatchSnapshot(); - - expect(unstableRenderSubtreeIntoContainer).not.toHaveBeenCalled(); - - unstableRenderSubtreeIntoContainer.mockReset(); - unstableRenderSubtreeIntoContainer.mockRestore(); - }); - - it('expect to render correctly without a marker', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow( - - This is the children. - , - { - disableLifecycleMethods: true, - } - ); - - expect(wrapper.type()).toBe(null); - }); - - it('expect to not render on didUpdate', () => { - const unstableRenderSubtreeIntoContainer = jest.spyOn( - ReactDOM, - 'unstable_renderSubtreeIntoContainer' - ); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - utils.registerEvents.mockImplementation(() => () => {}); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - // Use `mount` instead of `shallow` to trigger didUpdate - const wrapper = mount( - - This is the children. - - ); - - expect(unstableRenderSubtreeIntoContainer).not.toHaveBeenCalled(); - - wrapper.instance().componentDidUpdate(); - - expect(unstableRenderSubtreeIntoContainer).not.toHaveBeenCalled(); - - unstableRenderSubtreeIntoContainer.mockReset(); - unstableRenderSubtreeIntoContainer.mockRestore(); - }); - - it('expect to not call unmountComponentAtNode on willUnmount', () => { - const unmountComponentAtNode = jest.spyOn( - ReactDOM, - 'unmountComponentAtNode' - ); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow( - - This is the children. - - ); - - wrapper.unmount(); - - expect(unmountComponentAtNode).not.toHaveBeenCalled(); - - unmountComponentAtNode.mockReset(); - unmountComponentAtNode.mockRestore(); - }); - }); - - describe('with unstable_renderSubtreeIntoContainer', () => { - it('expect to render correctly', () => { - const unstableRenderSubtreeIntoContainer = jest.spyOn( - ReactDOM, - 'unstable_renderSubtreeIntoContainer' - ); - - const isReact16 = jest - .spyOn(CustomMarker, 'isReact16') - .mockImplementation(() => false); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - utils.registerEvents.mockImplementation(() => () => {}); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = mount( - - This is the children. - - ); - - expect(wrapper).toMatchSnapshot(); - - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledTimes(1); - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledWith( - wrapper.instance(), - This is the children., - marker.element - ); - - unstableRenderSubtreeIntoContainer.mockReset(); - unstableRenderSubtreeIntoContainer.mockRestore(); - - isReact16.mockReset(); - isReact16.mockRestore(); - }); - - it('expect to render correctly without a marker', () => { - const isReact16 = jest - .spyOn(CustomMarker, 'isReact16') - .mockImplementation(() => false); - - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow( - - This is the children. - , - { - disableLifecycleMethods: true, - } - ); - - expect(wrapper.type()).toBe(null); - - isReact16.mockReset(); - isReact16.mockRestore(); - }); - - it('expect to render on didUpdate', () => { - const unstableRenderSubtreeIntoContainer = jest.spyOn( - ReactDOM, - 'unstable_renderSubtreeIntoContainer' - ); - - const isReact16 = jest - .spyOn(CustomMarker, 'isReact16') - .mockImplementation(() => false); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - utils.registerEvents.mockImplementation(() => () => {}); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - // Use `mount` instead of `shallow` to avoid issue with `unstable_renderSubtreeIntoContainer` - const wrapper = mount( - - This is the children. - - ); - - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledTimes(1); - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledWith( - wrapper.instance(), - This is the children., - marker.element - ); - - wrapper.instance().componentDidUpdate(); - - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledTimes(2); - expect(unstableRenderSubtreeIntoContainer).toHaveBeenCalledWith( - wrapper.instance(), - This is the children., - marker.element - ); - - unstableRenderSubtreeIntoContainer.mockReset(); - unstableRenderSubtreeIntoContainer.mockRestore(); - - isReact16.mockReset(); - isReact16.mockRestore(); - }); - - it('expect to call unmountComponentAtNode on willUnmount', () => { - const unmountComponentAtNode = jest.spyOn( - ReactDOM, - 'unmountComponentAtNode' - ); - - const isReact16 = jest - .spyOn(CustomMarker, 'isReact16') - .mockImplementation(() => false); - - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - // Use `mount` instead of `shallow` to avoid issue with `unstable_renderSubtreeIntoContainer` - const wrapper = mount( - - This is the children. - - ); - - wrapper.unmount(); - - expect(unmountComponentAtNode).toHaveBeenCalledWith(marker.element); - - unmountComponentAtNode.mockReset(); - unmountComponentAtNode.mockRestore(); - - isReact16.mockReset(); - isReact16.mockRestore(); - }); - }); - - describe('Connected', () => { - it('expect to have access to Google Maps', () => { - const marker = createFakeHTMLMarkerInstance(); - const factory = jest.fn(() => marker); - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - createHTMLMarker.mockImplementationOnce(() => factory); - - const props = { - ...defaultProps, - }; - - mount( - - - This is the children. - - - ); - - expect(createHTMLMarker).toHaveBeenCalledWith(google); - - expect(factory).toHaveBeenCalledWith( - expect.objectContaining({ - map: mapInstance, - }) - ); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/GeoSearch.js b/packages/react-instantsearch-dom-maps/src/__tests__/GeoSearch.js deleted file mode 100644 index db081d5e0c..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/GeoSearch.js +++ /dev/null @@ -1,493 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import { createFakeGoogleReference } from '../../test/mockGoogleMaps'; -import GeoSearch from '../GeoSearch'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('GeoSearch', () => { - const ShallowWapper = ({ children }) => children; - - const defaultProps = { - google: createFakeGoogleReference(), - }; - - const defaultConnectorProps = { - hits: [], - isRefineOnMapMove: true, - hasMapMoveSinceLastRefine: false, - refine: () => {}, - toggleRefineOnMapMove: () => {}, - setMapMoveSinceLastRefine: () => {}, - }; - - const renderConnector = ({ props, connectorProps, children = () => null }) => - shallow({children}) - .find('[testID="Connector"]') - .props() - .children(connectorProps); - - describe('Connector', () => { - it('expect to render', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({() => null}); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with enableRefineOnMapMove', () => { - const props = { - ...defaultProps, - enableRefineOnMapMove: false, - }; - - const wrapper = shallow({() => null}); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with defaultRefinement', () => { - const props = { - ...defaultProps, - defaultRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const wrapper = shallow({() => null}); - - expect(wrapper).toMatchSnapshot(); - }); - }); - - describe('Provider', () => { - it('expect to render', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const renderPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - expect(renderPropsWrapper).toMatchSnapshot(); - }); - - it('expect to render with hits', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - hits: [ - { objectID: '0001' }, - { objectID: '0002' }, - { objectID: '0003' }, - ], - }; - - const renderPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerProps = renderPropsWrapper - .find('[testID="Provider"]') - .props(); - - expect(providerProps.hits).toEqual([ - { objectID: '0001' }, - { objectID: '0002' }, - { objectID: '0003' }, - ]); - }); - - it('expect to render with position', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - position: { - lat: 10, - lng: 12, - }, - }; - - const renderConnectorWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerProps = renderConnectorWrapper - .find('[testID="Provider"]') - .props(); - - expect(providerProps.position).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to render with currentRefinement', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - currentRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const renderConnectorWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerProps = renderConnectorWrapper - .find('[testID="Provider"]') - .props(); - - expect(providerProps.currentRefinement).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to render with enableRefine', () => { - const props = { - ...defaultProps, - enableRefine: false, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const renderConnectorWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerProps = renderConnectorWrapper - .find('[testID="Provider"]') - .props(); - - expect(providerProps.isRefineEnable).toBe(false); - }); - }); - - describe('GoogleMaps', () => { - const defaultProviderProps = { - onChange: () => {}, - onIdle: () => {}, - shouldUpdate: () => true, - }; - - const renderProvider = ({ connectorPropsWrapper, providerProps }) => - connectorPropsWrapper - .find('[testID="Provider"]') - .props() - .children(providerProps); - - it('expect to render', () => { - const children = jest.fn(() =>
Hello this is the children
); - - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps, children })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - expect(providerPropsWrapper).toMatchSnapshot(); - expect(children).toHaveBeenCalledWith({ hits: [] }); - }); - - it('expect to render with initialZoom', () => { - const props = { - ...defaultProps, - initialZoom: 8, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.initialZoom).toBe(8); - }); - - it('expect to render with postiion', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - position: { - lat: 10, - lng: 12, - }, - }; - - const providerProps = { - ...defaultProviderProps, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.initialPosition).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to render with initialPosition', () => { - const props = { - ...defaultProps, - initialPosition: { - lat: 10, - lng: 12, - }, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.initialPosition).toEqual({ - lat: 10, - lng: 12, - }); - }); - - it('expect to render with map options', () => { - const props = { - ...defaultProps, - streetViewControl: true, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.mapOptions).toEqual({ - streetViewControl: true, - }); - }); - - it('expect to render with boundingBox', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - boundingBox: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.boundingBox).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to render with boundingBoxPadding', () => { - const props = { - ...defaultProps, - }; - - const connectorProps = { - ...defaultConnectorProps, - }; - - const providerProps = { - ...defaultProviderProps, - boundingBoxPadding: 10, - }; - - const connectorPropsWrapper = shallow( - - {renderConnector({ props, connectorProps })} - - ); - - const providerPropsWrapper = shallow( - - {renderProvider({ connectorPropsWrapper, providerProps })} - - ); - - const googleMapProps = providerPropsWrapper - .find('[testID="GoogleMaps"]') - .props(); - - expect(googleMapProps.boundingBoxPadding).toBe(10); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMaps.js b/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMaps.js deleted file mode 100644 index aab89d90a5..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMaps.js +++ /dev/null @@ -1,635 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; - -import { - createFakeGoogleReference, - createFakeMapInstance, -} from '../../test/mockGoogleMaps'; -import GoogleMaps from '../GoogleMaps'; -import GoogleMapsContext from '../GoogleMapsContext'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('GoogleMaps', () => { - const defaultProps = { - google: createFakeGoogleReference(), - initialZoom: 1, - initialPosition: { - lat: 0, - lng: 0, - }, - mapOptions: {}, - onChange: () => {}, - onIdle: () => {}, - shouldUpdate: () => true, - position: null, - boundingBox: null, - }; - - const simulateMapReadyEvent = (google) => { - google.maps.event.addListenerOnce.mock.calls[0][2](); - }; - - const simulateEvent = (fn, eventName, event) => { - fn.addListener.mock.calls.find((call) => call.includes(eventName))[1]( - event - ); - }; - - it('expect render correctly without the map rendered', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('[testId]').exists()).toBe(false); - }); - - it('expect render correctly with the map rendered', () => { - const google = createFakeGoogleReference(); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('[testId]').exists()).toBe(false); - - simulateMapReadyEvent(google); - - expect(wrapper).toMatchSnapshot(); - expect(wrapper.find('[testId]').exists()).toBe(true); - }); - - describe('creation', () => { - it('expect to create the GoogleMaps on didMount with the default options', () => { - const google = createFakeGoogleReference(); - - const props = { - ...defaultProps, - google, - }; - - mount(); - - expect(google.maps.Map).toHaveBeenCalledTimes(1); - expect(google.maps.Map).toHaveBeenCalledWith(expect.any(HTMLDivElement), { - mapTypeControl: false, - fullscreenControl: false, - streetViewControl: false, - clickableIcons: false, - zoomControlOptions: { - position: 'left:top', - }, - }); - }); - - it('expect to create the GoogleMaps on didMount with the given options', () => { - const google = createFakeGoogleReference(); - - const props = { - ...defaultProps, - mapOptions: { - streetViewControl: true, - otherOptionToPass: false, - }, - google, - }; - - mount(); - - expect(google.maps.Map).toHaveBeenCalledTimes(1); - expect(google.maps.Map).toHaveBeenCalledWith(expect.any(HTMLDivElement), { - mapTypeControl: false, - fullscreenControl: false, - streetViewControl: true, - clickableIcons: false, - otherOptionToPass: false, - zoomControlOptions: { - position: 'left:top', - }, - }); - }); - - it('expect to listen "idle" event once to setup the rest of the listeners', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow(); - - expect(google.maps.event.addListenerOnce).toHaveBeenCalledTimes(1); - expect(google.maps.event.addListenerOnce).toHaveBeenCalledWith( - mapInstance, - 'idle', - expect.any(Function) - ); - - expect(wrapper.instance().listeners).toHaveLength(1); - }); - - it('expect to setup the rest of the listener when the map is ready', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow(); - - simulateMapReadyEvent(google); - - expect(mapInstance.addListener).toHaveBeenCalledWith( - 'center_changed', - expect.any(Function) - ); - - expect(mapInstance.addListener).toHaveBeenCalledWith( - 'zoom_changed', - expect.any(Function) - ); - - expect(mapInstance.addListener).toHaveBeenCalledWith( - 'dragstart', - expect.any(Function) - ); - - expect(mapInstance.addListener).toHaveBeenCalledWith( - 'idle', - expect.any(Function) - ); - - expect(wrapper.instance().listeners).toHaveLength(4); - }); - }); - - describe('events', () => { - it('expect to trigger idle callback', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - onIdle: jest.fn(), - google, - }; - - shallow(); - - simulateMapReadyEvent(google); - - expect(props.onIdle).toHaveBeenCalledTimes(0); - - simulateEvent(mapInstance, 'idle'); - - expect(props.onIdle).toHaveBeenCalledTimes(1); - expect(props.onIdle).toHaveBeenCalledWith({ - instance: mapInstance, - }); - }); - - it('expect to not trigger idle callback on programmatic interaction', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - onIdle: jest.fn(), - google, - }; - - const wrapper = shallow(); - - simulateMapReadyEvent(google); - - // Simulate fitBounds - wrapper.instance().isUserInteraction = false; - - expect(props.onIdle).toHaveBeenCalledTimes(0); - - simulateEvent(mapInstance, 'idle'); - - expect(props.onIdle).toHaveBeenCalledTimes(0); - }); - - ['center_changed', 'zoom_changed', 'dragstart'].forEach((eventName) => { - it(`expect to call change callback on "${eventName}"`, () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - onChange: jest.fn(), - google, - }; - - shallow(); - - simulateMapReadyEvent(google); - - expect(props.onChange).toHaveBeenCalledTimes(0); - - simulateEvent(mapInstance, eventName); - - expect(props.onChange).toHaveBeenCalledTimes(1); - }); - - it(`expect to not call change callback on "${eventName}" with programmatic interaction`, () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - onChange: jest.fn(), - google, - }; - - const wrapper = shallow(); - - simulateMapReadyEvent(google); - - expect(props.onChange).toHaveBeenCalledTimes(0); - - // Simulate fitBounds - wrapper.instance().isUserInteraction = false; - - simulateEvent(mapInstance, eventName); - - expect(props.onChange).toHaveBeenCalledTimes(0); - }); - }); - }); - - describe('context', () => { - it('expect to not expose the context when the map is not ready', () => { - const google = createFakeGoogleReference({}); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - - {() => null} - - ); - - expect(wrapper.find(GoogleMapsContext.Consumer).exists()).toBe(false); - }); - - it('expect to expose the context only when the map is created', () => { - const google = createFakeGoogleReference({}); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - - {() => null} - - ); - - simulateMapReadyEvent(google); - - expect(wrapper.find(GoogleMapsContext.Consumer).exists()).toBe(true); - }); - - it('expect to expose the map instance through context only when created', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const renderFn = jest.fn(() => null); - - mount( - - {renderFn} - - ); - - simulateMapReadyEvent(google); - - expect(renderFn).toHaveBeenCalledWith({ google, instance: mapInstance }); - }); - }); - - describe('update', () => { - it('expect to call fitBounds on didUpdate when boundingBox is provided', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - simulateMapReadyEvent(google); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(1); // cDM - expect(mapInstance.setCenter).toHaveBeenCalledTimes(1); // cDM - - wrapper.setProps({ - boundingBoxPadding: 0, - boundingBox: { - northEast: { - lat: 14, - lng: 14, - }, - southWest: { - lat: 10, - lng: 10, - }, - }, - }); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(1); - expect(mapInstance.fitBounds).toHaveBeenCalledWith( - expect.objectContaining({ - northEast: { - lat: 10, - lng: 10, - }, - southWest: { - lat: 14, - lng: 14, - }, - }), - 0 - ); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(1); // cDM - expect(mapInstance.setCenter).toHaveBeenCalledTimes(1); // cDM - }); - - it('expect not to call fitBounds on didUpdate when boundingBox equal to previous', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - simulateMapReadyEvent(google); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(1); // cDM - expect(mapInstance.setCenter).toHaveBeenCalledTimes(1); // cDM - - wrapper.setProps({ - boundingBoxPadding: 0, - boundingBox: { - northEast: { - lat: 10, - lng: 10, - }, - southWest: { - lat: 14, - lng: 14, - }, - }, - }); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(1); - expect(mapInstance.fitBounds).toHaveBeenCalledWith( - expect.objectContaining({ - northEast: { - lat: 14, - lng: 14, - }, - southWest: { - lat: 10, - lng: 10, - }, - }), - 0 - ); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(1); // cDM - expect(mapInstance.setCenter).toHaveBeenCalledTimes(1); // cDM - - mapInstance.getBounds.mockImplementation( - () => - new google.maps.LatLngBounds( - { lat: 14, lng: 14 }, - { lat: 10, lng: 10 } - ) - ); - - wrapper.setProps({ - boundingBoxPadding: 0, - boundingBox: { - northEast: { - lat: 10, - lng: 10, - }, - southWest: { - lat: 14, - lng: 14, - }, - }, - }); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(1); - }); - - it('expect to call setCenter & setZoom when boundingBox is not provided', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - google.maps.LatLngBounds.mockImplementation((sw, ne) => ({ - northEast: ne, - southWest: sw, - })); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - simulateMapReadyEvent(google); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(1); // cDM - expect(mapInstance.setCenter).toHaveBeenCalledTimes(1); // cDM - - wrapper.setProps(); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(2); // cDM + cDU - expect(mapInstance.setZoom).toHaveBeenCalledWith(1); - - expect(mapInstance.setCenter).toHaveBeenCalledTimes(2); // cDM + cDU - expect(mapInstance.setCenter).toHaveBeenCalledWith({ - lat: 0, - lng: 0, - }); - }); - - it('expect to prevent the map update when shouldUpdate return false', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - shouldUpdate: () => false, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - simulateMapReadyEvent(google); - simulateEvent(mapInstance, 'center_changed'); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(0); - expect(mapInstance.setCenter).toHaveBeenCalledTimes(0); - - wrapper.setProps(); - - expect(mapInstance.fitBounds).toHaveBeenCalledTimes(0); - - expect(mapInstance.setZoom).toHaveBeenCalledTimes(0); - expect(mapInstance.setCenter).toHaveBeenCalledTimes(0); - }); - - it('expect to still render the children when shouldUpdate return false', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - shouldUpdate: () => false, - google, - }; - - const wrapper = shallow( - -
This is the children
-
- ); - - simulateMapReadyEvent(google); - simulateEvent(mapInstance, 'center_changed'); - - expect(wrapper.find('.children')).toMatchSnapshot(); - - wrapper.setProps({ - children:
This is the children updated
, - }); - - expect(wrapper.find('.children')).toMatchSnapshot(); - }); - }); - - describe('delete', () => { - it('expect to remove all the listeners', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - google, - }; - - const wrapper = shallow(); - - simulateMapReadyEvent(google); - - expect(wrapper.instance().listeners).toHaveLength(4); - - const internalListeners = wrapper.instance().listeners.slice(); - - wrapper.unmount(); - - internalListeners.forEach((listener) => { - expect(listener.remove).toHaveBeenCalledTimes(1); - }); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.jsdom.js b/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.jsdom.js deleted file mode 100644 index 15acb4e906..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.jsdom.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { wait } from '@instantsearch/testutils'; -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; -import injectScript from 'scriptjs'; - -import GoogleMapsLoader from '../GoogleMapsLoader'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('scriptjs'); - -describe('GoogleMapsLoader', () => { - const defaultProps = { - apiKey: 'API_KEY', - }; - - it('expect to call Google Maps API', async () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - await wait(0); - - expect(injectScript).toHaveBeenLastCalledWith( - 'https://maps.googleapis.com/maps/api/js?v=quarterly&key=API_KEY', - expect.any(Function) - ); - }); - - it('expect to call Google Maps API with a custom API Key', async () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - apiKey: 'CUSTOM_API_KEY', - }; - - shallow({children}); - - await wait(0); - - expect(injectScript).toHaveBeenLastCalledWith( - 'https://maps.googleapis.com/maps/api/js?v=quarterly&key=CUSTOM_API_KEY', - expect.any(Function) - ); - }); - - it('expect to call Google Maps API with a custom endpoint', async () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - endpoint: - 'https://maps.googleapis.com/maps/api/js?v=3.32&places,geometry', - }; - - shallow({children}); - - await wait(0); - - expect(injectScript).toHaveBeenLastCalledWith( - 'https://maps.googleapis.com/maps/api/js?v=3.32&places,geometry&key=API_KEY', - expect.any(Function) - ); - }); - - it("expect to render nothing when it's loading", () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - const wrapper = shallow( - {children} - ); - - expect(wrapper.type()).toBe(null); - expect(children).not.toHaveBeenCalled(); - }); - - it("expect to call children with the Google object when it's loaded", async () => { - const children = jest.fn((x) => x); - - const google = { - version: '3.1.1', - }; - - const props = { - ...defaultProps, - }; - - injectScript.mockImplementationOnce((_, callback) => { - global.google = google; - callback(); - }); - - const wrapper = shallow( - {children} - ); - - await wait(0); - - expect(wrapper.type).not.toBe(null); - expect(children).toHaveBeenCalledTimes(1); - expect(children).toHaveBeenCalledWith(google); - - delete global.google; - }); - - it('expect to not call setState when we unmount before loading is complete', async () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - let triggerLoadingComplete; - injectScript.mockImplementationOnce((endpoint, callback) => { - triggerLoadingComplete = callback; - }); - - const wrapper = shallow( - {children} - ); - - await wait(0); - - expect(wrapper.type).not.toBe(null); - expect(children).not.toHaveBeenCalled(); - - wrapper.unmount(); - - triggerLoadingComplete(); - - expect(children).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.node.js b/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.node.js deleted file mode 100644 index 998df5d5a5..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/GoogleMapsLoader.node.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @jest-environment node - */ - -describe('GoogleMapsLoader', () => { - it('expect to require the file in a Node environment', () => { - expect(() => require('../GoogleMapsLoader')).not.toThrow(); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/Marker.js b/packages/react-instantsearch-dom-maps/src/__tests__/Marker.js deleted file mode 100644 index e87034b680..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/Marker.js +++ /dev/null @@ -1,280 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; - -import { - createFakeGoogleReference, - createFakeMapInstance, - createFakeMarkerInstance, -} from '../../test/mockGoogleMaps'; -import GoogleMapsContext from '../GoogleMapsContext'; -import Connected, { Marker } from '../Marker'; -import * as utils from '../utils'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('../utils', () => { - const module = jest.requireActual('../utils'); - - return { - registerEvents: jest.fn(), - createFilterProps: module.createFilterProps, - createListenersPropTypes: module.createListenersPropTypes, - }; -}); - -describe('Marker', () => { - const defaultProps = { - hit: { - _geoloc: { - lat: 10, - lng: 12, - }, - }, - }; - - beforeEach(() => { - utils.registerEvents.mockClear(); - utils.registerEvents.mockReset(); - }); - - it('expect render correctly', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow(); - - expect(wrapper.type()).toBe(null); - }); - - describe('creation', () => { - it('expect to create the Marker on didMount with default options', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(google.maps.Marker).not.toHaveBeenCalled(); - - // Simulate didMount - wrapper.instance().componentDidMount(); - - expect(google.maps.Marker).toHaveBeenCalledTimes(1); - expect(google.maps.Marker).toHaveBeenCalledWith({ - map: mapInstance, - position: { - lat: 10, - lng: 12, - }, - }); - }); - - it('expect to create the Marker on didMount with given options', () => { - const mapInstance = createFakeMapInstance(); - const google = createFakeGoogleReference({ - mapInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - title: 'My Marker', - visible: false, - children: , - onClick: () => {}, - google, - }; - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(google.maps.Marker).not.toHaveBeenCalled(); - - // Simulate didMount - wrapper.instance().componentDidMount(); - - expect(google.maps.Marker).toHaveBeenCalledTimes(1); - expect(google.maps.Marker).toHaveBeenCalledWith({ - title: 'My Marker', - visible: false, - map: mapInstance, - position: { - lat: 10, - lng: 12, - }, - }); - }); - - it('expect to register the listeners on didMount', () => { - const mapInstance = createFakeMapInstance(); - const markerInstance = createFakeMarkerInstance(); - const google = createFakeGoogleReference({ - mapInstance, - markerInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow(, { - disableLifecycleMethods: true, - }); - - expect(utils.registerEvents).toHaveBeenCalledTimes(0); - - // Simulate didMount - wrapper.instance().componentDidMount(); - - expect(utils.registerEvents).toHaveBeenCalledTimes(1); - expect(utils.registerEvents).toHaveBeenCalledWith( - expect.any(Object), - expect.any(Object), - markerInstance - ); - }); - }); - - describe('update', () => { - it('expect to remove the listener on didUpdate', () => { - const removeEventListeners = jest.fn(); - const mapInstance = createFakeMapInstance(); - const markerInstance = createFakeMarkerInstance(); - const google = createFakeGoogleReference({ - mapInstance, - markerInstance, - }); - - utils.registerEvents.mockImplementation(() => removeEventListeners); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow(); - - expect(removeEventListeners).toHaveBeenCalledTimes(0); - - // Simulate the update - wrapper.instance().componentDidUpdate(); - - expect(removeEventListeners).toHaveBeenCalledTimes(1); - }); - - it('expect to register the listeners on didUpdate', () => { - const mapInstance = createFakeMapInstance(); - const markerInstance = createFakeMarkerInstance(); - const google = createFakeGoogleReference({ - mapInstance, - markerInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - utils.registerEvents.mockImplementationOnce(() => () => {}); - - const wrapper = shallow(); - - expect(utils.registerEvents).toHaveBeenCalledTimes(1); - - // Simulate the update - wrapper.instance().componentDidUpdate(); - - expect(utils.registerEvents).toHaveBeenCalledTimes(2); - expect(utils.registerEvents).toHaveBeenLastCalledWith( - expect.any(Object), - expect.any(Object), - markerInstance - ); - }); - }); - - describe('delete', () => { - it('expect to remove the Marker on willUnmount', () => { - const mapInstance = createFakeMapInstance(); - const markerInstance = createFakeMarkerInstance(); - const google = createFakeGoogleReference({ - mapInstance, - markerInstance, - }); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - google, - }; - - const wrapper = shallow(); - - wrapper.unmount(); - - expect(markerInstance.setMap).toHaveBeenCalledTimes(1); - expect(markerInstance.setMap).toHaveBeenCalledWith(null); - }); - }); - - describe('Connected', () => { - it('expect to have access to Google Maps', () => { - const mapInstance = createFakeMapInstance(); - const markerInstance = createFakeMarkerInstance(); - const google = createFakeGoogleReference({ - mapInstance, - markerInstance, - }); - - const props = { - ...defaultProps, - }; - - mount( - - - - ); - - expect(google.maps.Marker).toHaveBeenCalledWith({ - map: mapInstance, - position: { - lat: 10, - lng: 12, - }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/Provider.js b/packages/react-instantsearch-dom-maps/src/__tests__/Provider.js deleted file mode 100644 index 2b6c01d5c9..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/Provider.js +++ /dev/null @@ -1,531 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import { - createFakeGoogleReference, - createFakeMapInstance, -} from '../../test/mockGoogleMaps'; -import Provider from '../Provider'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Provider', () => { - const defaultProps = { - google: createFakeGoogleReference(), - hits: [], - initialPosition: { lat: 0, lng: 0 }, - isRefineOnMapMove: true, - hasMapMoveSinceLastRefine: false, - isRefineEnable: true, - refine: () => {}, - toggleRefineOnMapMove: () => {}, - setMapMoveSinceLastRefine: () => {}, - children: () => {}, - }; - - const lastRenderArgs = (fn) => fn.mock.calls[fn.mock.calls.length - 1][0]; - - it('expect to render with default props', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - expect(children).toHaveBeenCalledTimes(1); - expect(children).toHaveBeenCalledWith({ - boundingBox: undefined, - boundingBoxPadding: undefined, - onChange: expect.any(Function), - onIdle: expect.any(Function), - shouldUpdate: expect.any(Function), - }); - }); - - describe('boundingBox', () => { - it('expect to use hits when currentRefinement is not defined and hits are not empty', () => { - const children = jest.fn((x) => x); - const google = createFakeGoogleReference(); - - google.maps.LatLngBounds.mockImplementation(() => ({ - extend: jest.fn().mockReturnThis(), - getNorthEast: () => ({ - toJSON: () => ({ - lat: 10, - lng: 10, - }), - }), - getSouthWest: () => ({ - toJSON: () => ({ - lat: 14, - lng: 14, - }), - }), - })); - - const props = { - ...defaultProps, - hits: [ - { _geoloc: { lat: 10, lng: 12 } }, - { _geoloc: { lat: 12, lng: 14 } }, - ], - google, - }; - - shallow({children}); - - expect(lastRenderArgs(children).boundingBox).toEqual({ - northEast: { - lat: 10, - lng: 10, - }, - southWest: { - lat: 14, - lng: 14, - }, - }); - }); - - it("expect to use currentRefinement when it's defined and hits are empty", () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - currentRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - shallow({children}); - - expect(lastRenderArgs(children).boundingBox).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it("expect to use currentRefinement when it's defined and hits are not empty", () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - hits: [ - { _geoloc: { lat: 10, lng: 12 } }, - { _geoloc: { lat: 12, lng: 14 } }, - ], - currentRefinement: { - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }, - }; - - shallow({children}); - - expect(lastRenderArgs(children).boundingBox).toEqual({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it("expect to use currentRefinement when it's not defined and hits are empty", () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - expect(lastRenderArgs(children).boundingBox).toBe(undefined); - }); - }); - - describe('onChange', () => { - it('expect to call setMapMoveSinceLast refine', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - setMapMoveSinceLastRefine: jest.fn(), - }; - - shallow({children}); - - expect(props.setMapMoveSinceLastRefine).toHaveBeenCalledTimes(0); - - lastRenderArgs(children).onChange(); - - expect(props.setMapMoveSinceLastRefine).toHaveBeenCalledTimes(1); - expect(props.setMapMoveSinceLastRefine).toHaveBeenCalledWith(true); - }); - - it('expect to schedule a refine call when refine on map move is enabled', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - const wrapper = shallow({children}); - - expect(wrapper.instance().isPendingRefine).toBe(false); - - lastRenderArgs(children).onChange(); - - expect(wrapper.instance().isPendingRefine).toBe(true); - }); - - it('expect to not schedule a refine call when refine on map move is disabled', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - isRefineOnMapMove: false, - }; - - const wrapper = shallow({children}); - - expect(wrapper.instance().isPendingRefine).toBe(false); - - lastRenderArgs(children).onChange(); - - expect(wrapper.instance().isPendingRefine).toBe(false); - }); - - it('expect to do nothing when refine is disabled', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - isRefineEnable: false, - setMapMoveSinceLastRefine: jest.fn(), - }; - - const wrapper = shallow({children}); - - expect(wrapper.instance().isPendingRefine).toBe(false); - - lastRenderArgs(children).onChange(); - - expect(wrapper.instance().isPendingRefine).toBe(false); - expect(props.setMapMoveSinceLastRefine).not.toHaveBeenCalled(); - }); - }); - - describe('onIdle', () => { - it('expect to call refine when there is a pending refinement', () => { - const mapInstance = createFakeMapInstance(); - const children = jest.fn((x) => x); - - mapInstance.getBounds.mockImplementation(() => ({ - getNorthEast: () => ({ - toJSON: () => ({ - lat: 10, - lng: 12, - }), - }), - getSouthWest: () => ({ - toJSON: () => ({ - lat: 12, - lng: 14, - }), - }), - })); - - const props = { - ...defaultProps, - refine: jest.fn(), - }; - - shallow({children}); - - lastRenderArgs(children).onChange(); - lastRenderArgs(children).onIdle({ instance: mapInstance }); - - expect(props.refine).toHaveBeenCalledTimes(1); - expect(props.refine).toHaveBeenCalledWith({ - northEast: { - lat: 10, - lng: 12, - }, - southWest: { - lat: 12, - lng: 14, - }, - }); - }); - - it('expect to reset the pending refinement when there is a pending refinement', () => { - const mapInstance = createFakeMapInstance(); - const children = jest.fn((x) => x); - - mapInstance.getBounds.mockImplementation(() => ({ - getNorthEast: () => ({ - toJSON: () => {}, - }), - getSouthWest: () => ({ - toJSON: () => {}, - }), - })); - - const props = { - ...defaultProps, - refine: jest.fn(), - }; - - const wrapper = shallow({children}); - - lastRenderArgs(children).onChange(); - - expect(wrapper.instance().isPendingRefine).toBe(true); - - lastRenderArgs(children).onIdle({ instance: mapInstance }); - - expect(wrapper.instance().isPendingRefine).toBe(false); - }); - - it('expect to do nothing when there is no pending refinement', () => { - const mapInstance = createFakeMapInstance(); - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - refine: jest.fn(), - setMapMoveSinceLastRefine: jest.fn(), - }; - - const wrapper = shallow({children}); - - expect(wrapper.instance().isPendingRefine).toBe(false); - - lastRenderArgs(children).onIdle({ instance: mapInstance }); - - expect(wrapper.instance().isPendingRefine).toBe(false); - expect(props.refine).not.toHaveBeenCalled(); - expect(props.setMapMoveSinceLastRefine).not.toHaveBeenCalled(); - }); - }); - - describe('shouldUpdate', () => { - it("expect to return true when no refinement is pending and the map didn't moved", () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - const actual = lastRenderArgs(children).shouldUpdate(); - - expect(actual).toBe(true); - }); - - it('expect to return false when there is a pending refinement', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - }; - - shallow({children}); - - lastRenderArgs(children).onChange(); - - const actual = lastRenderArgs(children).shouldUpdate(); - - expect(actual).toBe(false); - }); - - it('expect to return false when the map has moved', () => { - const children = jest.fn((x) => x); - - const props = { - ...defaultProps, - hasMapMoveSinceLastRefine: true, - }; - - shallow({children}); - - const actual = lastRenderArgs(children).shouldUpdate(); - - expect(actual).toBe(false); - }); - }); - - describe('context', () => { - it('expect to expose isRefineOnMapMove', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({(x) => x}); - - expect(wrapper.props().value.isRefineOnMapMove).toBe(true); - }); - - it('expect to expose hasMapMoveSinceLastRefine', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({(x) => x}); - - expect(wrapper.props().value.hasMapMoveSinceLastRefine).toBe(false); - }); - - it('expect to expose toggleRefineOnMapMove', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({(x) => x}); - - expect(wrapper.props().value.toggleRefineOnMapMove).toBe( - props.toggleRefineOnMapMove - ); - }); - - it('expect to expose setMapMoveSinceLastRefine', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({(x) => x}); - - expect(wrapper.props().value.setMapMoveSinceLastRefine).toBe( - props.setMapMoveSinceLastRefine - ); - }); - - it('expect to expose refineWithInstance', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow({(x) => x}); - - expect(wrapper.props().value.refineWithInstance).toBe( - wrapper.instance().refineWithInstance - ); - }); - - it('expect to pass new mapValue reference when isRefineOnMapMove changes', () => { - const props = { - ...defaultProps, - isRefineOnMapMove: true, - }; - - const wrapper = shallow(); - const mapValue = wrapper.instance().mapValue; - - expect(mapValue).toBe(wrapper.instance().mapValue); - - wrapper.setProps({ - isRefineOnMapMove: false, - }); - - expect(mapValue).not.toBe(wrapper.instance().mapValue); - }); - - it('expect to pass new mapValue reference when hasMapMoveSinceLastRefine changes', () => { - const props = { - ...defaultProps, - hasMapMoveSinceLastRefine: false, - }; - - const wrapper = shallow(); - const mapValue = wrapper.instance().mapValue; - - expect(mapValue).toBe(wrapper.instance().mapValue); - - wrapper.setProps({ - hasMapMoveSinceLastRefine: true, - }); - - expect(mapValue).not.toBe(wrapper.instance().mapValue); - }); - - it('expect to pass same mapValue reference when toggleRefineOnMapMove changes', () => { - const props = { - ...defaultProps, - toggleRefineOnMapMove: jest.fn(), - }; - - const wrapper = shallow(); - const mapValue = wrapper.instance().mapValue; - - expect(mapValue).toBe(wrapper.instance().mapValue); - - wrapper.setProps({ - toggleRefineOnMapMove: jest.fn(), - }); - - expect(mapValue).toBe(wrapper.instance().mapValue); - }); - - it('expect to pass same mapValue reference when setMapMoveSinceLastRefine changes', () => { - const props = { - ...defaultProps, - setMapMoveSinceLastRefine: jest.fn(), - }; - - const wrapper = shallow(); - const mapValue = wrapper.instance().mapValue; - - expect(mapValue).toBe(wrapper.instance().mapValue); - - wrapper.setProps({ - setMapMoveSinceLastRefine: jest.fn(), - }); - - expect(mapValue).toBe(wrapper.instance().mapValue); - }); - - it('expect to pass same mapValue reference when refineWithInstance changes', () => { - const props = { - ...defaultProps, - refineWithInstance: jest.fn(), - }; - - const wrapper = shallow(); - const mapValue = wrapper.instance().mapValue; - - expect(mapValue).toBe(wrapper.instance().mapValue); - - wrapper.setProps({ - refineWithInstance: jest.fn(), - }); - - expect(mapValue).toBe(wrapper.instance().mapValue); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/Redo.js b/packages/react-instantsearch-dom-maps/src/__tests__/Redo.js deleted file mode 100644 index c9ccbfddeb..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/Redo.js +++ /dev/null @@ -1,60 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import { createFakeMapInstance } from '../../test/mockGoogleMaps'; -import { Redo } from '../Redo'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Redo', () => { - const defaultProps = { - googleMapsInstance: createFakeMapInstance(), - translate: (x) => x, - - hasMapMoveSinceLastRefine: false, - refineWithInstance: () => {}, - }; - - it('expect to render correctly', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow(); - - expect(wrapper.find('button').prop('disabled')).toBe(true); - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render correctly when map has moved', () => { - const props = { - ...defaultProps, - hasMapMoveSinceLastRefine: true, - }; - - const wrapper = shallow(); - - expect(wrapper.find('button').prop('disabled')).toBe(false); - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to call refineWithInstance on button click', () => { - const mapInstance = createFakeMapInstance(); - - const props = { - ...defaultProps, - googleMapsInstance: mapInstance, - refineWithInstance: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.refineWithInstance).toHaveBeenCalledTimes(0); - - wrapper.find('button').simulate('click'); - - expect(props.refineWithInstance).toHaveBeenCalledTimes(1); - expect(props.refineWithInstance).toHaveBeenCalledWith(mapInstance); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Control.js.snap b/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Control.js.snap deleted file mode 100644 index 45ece491dd..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Control.js.snap +++ /dev/null @@ -1,50 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Control expect to render correctly with refine on map move 1`] = ` -
- -
-`; - -exports[`Control expect to render correctly without refine on map move 1`] = ` -
- -
-`; - -exports[`Control expect to render correctly without refine on map move when the map has moved 1`] = ` -
- -
-`; diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/CustomMarker.js.snap b/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/CustomMarker.js.snap deleted file mode 100644 index cb00283cfa..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/CustomMarker.js.snap +++ /dev/null @@ -1,113 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CustomMarker with portal expect to render correctly 1`] = ` - - - - This is the children. - -
- } - > - - This is the children. - - - -`; - -exports[`CustomMarker with unstable_renderSubtreeIntoContainer expect to render correctly 1`] = ` - -`; diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GeoSearch.js.snap b/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GeoSearch.js.snap deleted file mode 100644 index cfb348aa19..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GeoSearch.js.snap +++ /dev/null @@ -1,112 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GeoSearch Connector expect to render 1`] = ` - - - -`; - -exports[`GeoSearch Connector expect to render with defaultRefinement 1`] = ` - - - -`; - -exports[`GeoSearch Connector expect to render with enableRefineOnMapMove 1`] = ` - - - -`; - -exports[`GeoSearch GoogleMaps expect to render 1`] = ` - -
- Hello this is the children -
-
-`; - -exports[`GeoSearch Provider expect to render 1`] = ` - - - -`; diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GoogleMaps.js.snap b/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GoogleMaps.js.snap deleted file mode 100644 index a1dd5e5bf1..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/GoogleMaps.js.snap +++ /dev/null @@ -1,355 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`GoogleMaps expect render correctly with the map rendered 1`] = ` -
-
-
-`; - -exports[`GoogleMaps expect render correctly with the map rendered 2`] = ` -
-
- -
- This is the children -
-
-
-`; - -exports[`GoogleMaps expect render correctly without the map rendered 1`] = ` -
-
-
-`; - -exports[`GoogleMaps update expect to still render the children when shouldUpdate return false 1`] = ` -
- This is the children -
-`; - -exports[`GoogleMaps update expect to still render the children when shouldUpdate return false 2`] = ` -
- This is the children updated -
-`; diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Redo.js.snap b/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Redo.js.snap deleted file mode 100644 index 27ca8f25a3..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/__snapshots__/Redo.js.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Redo expect to render correctly 1`] = ` -
- -
-`; - -exports[`Redo expect to render correctly when map has moved 1`] = ` -
- -
-`; diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/utils.js b/packages/react-instantsearch-dom-maps/src/__tests__/utils.js deleted file mode 100644 index aa45878543..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/utils.js +++ /dev/null @@ -1,235 +0,0 @@ -import PropTypes from 'prop-types'; - -import { createFakeMarkerInstance } from '../../test/mockGoogleMaps'; -import * as utils from '../utils'; - -describe('utils', () => { - describe('registerEvents', () => { - it('expect to add listeners from events', () => { - const onClick = () => {}; - const onMouseMove = () => {}; - const instance = createFakeMarkerInstance(); - - const events = { - onClick: 'click', - onMouseMove: 'mousemove', - }; - - const props = { - onClick, - onMouseMove, - }; - - utils.registerEvents(events, props, instance); - - expect(instance.addListener).toHaveBeenCalledTimes(2); - - expect(instance.addListener).toHaveBeenCalledWith( - 'click', - expect.any(Function) - ); - - expect(instance.addListener).toHaveBeenCalledWith( - 'mousemove', - expect.any(Function) - ); - }); - - it('expect to add listeners with event & marker', () => { - const onClick = jest.fn(); - const onMouseMove = jest.fn(); - const instance = createFakeMarkerInstance(); - const listeners = []; - - instance.addListener.mockImplementation((event, listener) => - listeners.push(listener) - ); - - const events = { - onClick: 'click', - onMouseMove: 'mousemove', - }; - - const props = { - onClick, - onMouseMove, - }; - - utils.registerEvents(events, props, instance); - - listeners.forEach((listener) => listener({ type: 'event' })); - - expect(onClick).toHaveBeenCalledWith({ - event: { type: 'event' }, - marker: instance, - }); - - expect(onMouseMove).toHaveBeenCalledWith({ - event: { type: 'event' }, - marker: instance, - }); - }); - - it('expect to only add listeners listed from events', () => { - const onClick = () => {}; - const onMouseEnter = () => {}; - const instance = createFakeMarkerInstance(); - - const events = { - onClick: 'click', - onMouseMove: 'mousemove', - }; - - const props = { - onClick, - onMouseEnter, - }; - - utils.registerEvents(events, props, instance); - - expect(instance.addListener).toHaveBeenCalledTimes(1); - expect(instance.addListener).toHaveBeenCalledWith( - 'click', - expect.any(Function) - ); - }); - - it('expect to only add listeners listed from props', () => { - const onClick = () => {}; - const instance = createFakeMarkerInstance(); - - const events = { - onClick: 'click', - onMouseMove: 'mousemove', - }; - - const props = { - onClick, - }; - - utils.registerEvents(events, props, instance); - - expect(instance.addListener).toHaveBeenCalledTimes(1); - expect(instance.addListener).toHaveBeenCalledWith( - 'click', - expect.any(Function) - ); - }); - - it('expect to return a function that remove the listeners', () => { - const onClick = () => {}; - const onMouseMove = () => {}; - const remove = jest.fn(); - const instance = createFakeMarkerInstance(); - - instance.addListener.mockImplementation(() => ({ - remove, - })); - - const events = { - onClick: 'click', - onMouseMove: 'mousemove', - }; - - const props = { - onClick, - onMouseMove, - }; - - const removeEventListeners = utils.registerEvents( - events, - props, - instance - ); - - expect(remove).toHaveBeenCalledTimes(0); - - removeEventListeners(); - - expect(remove).toHaveBeenCalledTimes(2); - }); - }); - - describe('createListenersPropTypes', () => { - it('expect to return an object with listeners propType from event types', () => { - const events = { - onClick: '', - onMouseMove: '', - }; - - const expectation = { - onClick: PropTypes.func, - onMouseMove: PropTypes.func, - }; - - const actual = utils.createListenersPropTypes(events); - - expect(actual).toEqual(expectation); - }); - - it('expect to return an empty object from empty event types', () => { - const events = {}; - - const expectation = {}; - const actual = utils.createListenersPropTypes(events); - - expect(actual).toEqual(expectation); - }); - }); - - describe('createFilterProps', () => { - it('expect to return an object without excluded keys', () => { - const excludes = ['children', 'onClick']; - - const props = { - label: 'Title', - onClick: () => {}, - children: '
', - }; - - const expectation = { - label: 'Title', - }; - - const filterProps = utils.createFilterProps(excludes); - const actual = filterProps(props); - - expect(actual).toEqual(expectation); - }); - - it('expect to return the given props when excluded keys is empty', () => { - const onClick = () => {}; - const excludes = []; - - const props = { - children: '
', - onClick, - }; - - const expectation = { - children: '
', - onClick, - }; - - const filterProps = utils.createFilterProps(excludes); - const actual = filterProps(props); - - expect(actual).toEqual(expectation); - }); - - it('expect to return an empty object when all keys are excluded', () => { - const excludes = ['children', 'onClick']; - - const props = { - onClick: () => {}, - children: '
', - }; - - const expectation = {}; - const filterProps = utils.createFilterProps(excludes); - const actual = filterProps(props); - - expect(actual).toEqual(expectation); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/__tests__/withGoogleMaps.tsx b/packages/react-instantsearch-dom-maps/src/__tests__/withGoogleMaps.tsx deleted file mode 100644 index a56cb63e46..0000000000 --- a/packages/react-instantsearch-dom-maps/src/__tests__/withGoogleMaps.tsx +++ /dev/null @@ -1,106 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; - -import GoogleMapsContext from '../GoogleMapsContext'; -import withGoogleMaps from '../withGoogleMaps'; - -import type { GoogleMapsContextState } from '../GoogleMapsContext'; -import type { WithGoogleMapsProps } from '../withGoogleMaps'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('withGoogleMaps', () => { - interface Props extends WithGoogleMapsProps { - value: number; - } - - const createFakeContext = ({ - google = {} as any, - googleMapsInstance = {} as any, - }): GoogleMapsContextState => ({ - instance: googleMapsInstance, - google, - }); - - it('expect to inject `google` prop', () => { - const fakeGoogle: any = { - maps: { - visualization: { - HeatmapLayer: jest.fn(() => ({ - getMap() { - return null; - }, - })), - }, - }, - }; - - const Fake = withGoogleMaps(({ google }: Props) => { - const heatmap = new google.maps.visualization.HeatmapLayer({ - // Google Maps expects `LatLng | WeightedLocation` but we don't have access to the whole `google` - // instance in the test. - // We use `data` just to make sure that `Fake` correctly calls `HeatmapLayer` so the type issue is fine. - data: [10, 20, 30] as any, - radius: 50, - }); - - heatmap.getMap(); - - return null; - }); - - mount( - - - - ); - - expect(fakeGoogle.maps.visualization.HeatmapLayer).toHaveBeenCalledWith({ - data: [10, 20, 30], - radius: 50, - }); - }); - - it('expect to inject `googleMapsInstance` prop', () => { - const fakeGoogleMapsInstance: any = { - fitBounds: jest.fn(), - }; - - const Fake = withGoogleMaps(({ googleMapsInstance }: Props) => { - googleMapsInstance.fitBounds({ - north: 10, - east: 12, - south: 14, - west: 16, - }); - - return null; - }); - - mount( - - - - ); - - expect(fakeGoogleMapsInstance.fitBounds).toHaveBeenCalledWith({ - north: 10, - east: 12, - south: 14, - west: 16, - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/elements/__tests__/createHTMLMarker.js b/packages/react-instantsearch-dom-maps/src/elements/__tests__/createHTMLMarker.js deleted file mode 100644 index 56ab568952..0000000000 --- a/packages/react-instantsearch-dom-maps/src/elements/__tests__/createHTMLMarker.js +++ /dev/null @@ -1,261 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import { createFakeGoogleReference } from '../../../test/mockGoogleMaps'; -import createHTMLMarker from '../createHTMLMarker'; - -describe('createHTMLMarker', () => { - const createFakeParams = ({ ...rest } = {}) => ({ - position: { - lat: 10, - lng: 12, - }, - map: 'map-instance-placeholder', - className: 'ais-geo-search-marker', - ...rest, - }); - - it('expect to create a marker', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - - const marker = new HTMLMarker(params); - - expect(marker.anchor).toEqual({ x: 0, y: 0 }); - expect(marker.subscriptions).toEqual([]); - expect(marker.latLng).toEqual({ lat: 10, lng: 12 }); - - expect(marker.element).toEqual(expect.any(HTMLDivElement)); - expect(marker.element.className).toBe('ais-geo-search-marker'); - expect(marker.element.style.position).toBe('absolute'); - expect(marker.element.style.whiteSpace).toBe('nowrap'); - - expect(marker.setMap).toHaveBeenCalledWith('map-instance-placeholder'); - }); - - it('expect to create a marker with a custom anchor', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams({ - anchor: { - x: 5, - y: 10, - }, - }); - - const marker = new HTMLMarker(params); - - expect(marker.anchor).toEqual({ x: 5, y: 10 }); - }); - - it('expect to create a marker with a custom className', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams({ - className: 'my-custom-marker', - }); - - const marker = new HTMLMarker(params); - - expect(marker.element.className).toBe('my-custom-marker'); - }); - - describe('onAdd', () => { - it('expect to append the element to the overlay', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const overlayMouseTarget = { - appendChild: jest.fn(), - }; - - const marker = new HTMLMarker(params); - - marker.getPanes.mockImplementation(() => ({ overlayMouseTarget })); - - marker.onAdd(); - - expect(overlayMouseTarget.appendChild).toHaveBeenCalledWith( - marker.element - ); - }); - - it('expect to not append the element to the overlay when panes are not available', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const overlayMouseTarget = { - appendChild: jest.fn(), - }; - - const marker = new HTMLMarker(params); - - marker.getPanes.mockImplementation(() => null); - - marker.onAdd(); - - expect(overlayMouseTarget.appendChild).not.toHaveBeenCalled(); - }); - }); - - describe('draw', () => { - it('expect to set the correct position on the element', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const fromLatLngToDivPixel = jest.fn(() => ({ - x: 100, - y: 50, - })); - - const marker = new HTMLMarker(params); - - marker.getProjection.mockImplementation(() => ({ - fromLatLngToDivPixel, - })); - - marker.draw(); - - expect(fromLatLngToDivPixel).toHaveBeenCalledWith({ lat: 10, lng: 12 }); - expect(marker.element.style.left).toBe('100px'); - expect(marker.element.style.top).toBe('50px'); - }); - - it('expect to set the correct zIndex on the element', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const fromLatLngToDivPixel = jest.fn(() => ({ - x: 100, - y: 50, - })); - - const marker = new HTMLMarker(params); - - marker.getProjection.mockImplementationOnce(() => ({ - fromLatLngToDivPixel, - })); - - marker.draw(); - - expect(marker.element.style.zIndex).toBe('0'); - }); - - it('expect to not set the correct position when the projection is not available', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - - const marker = new HTMLMarker(params); - - marker.getProjection.mockImplementation(() => null); - - marker.draw(); - - expect(marker.element.style.left).toBe(''); - expect(marker.element.style.top).toBe(''); - expect(marker.element.style.zIndex).toBe(''); - }); - }); - - describe('onRemove', () => { - it('expect to remove the element', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - - const marker = new HTMLMarker(params); - - // Simulate the parentNode - const parentNode = document.createElement('div'); - parentNode.appendChild(marker.element); - - expect(parentNode.childNodes).toHaveLength(1); - - marker.onRemove(); - - expect(parentNode.childNodes).toHaveLength(0); - expect(marker.element).toBe(undefined); - }); - - it('expect to remove all the listeners', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const remove = jest.fn(); - - const marker = new HTMLMarker(params); - - // Simulate the parentNode - const parentNode = document.createElement('div'); - parentNode.appendChild(marker.element); - - // Simulate the subscriptions - marker.subscriptions.push({ remove }); - marker.subscriptions.push({ remove }); - - marker.onRemove(); - - expect(marker.subscriptions).toEqual([]); - expect(remove).toHaveBeenCalledTimes(2); - }); - }); - - describe('addListener', () => { - it('expect to register listener', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const onClick = () => {}; - - const marker = new HTMLMarker(params); - - const addEventListener = jest.spyOn(marker.element, 'addEventListener'); - - marker.addListener('click', onClick); - - expect(addEventListener).toHaveBeenCalledTimes(1); - expect(addEventListener).toHaveBeenCalledWith('click', onClick); - expect(marker.subscriptions).toHaveLength(1); - }); - - it('expect to return a function to remove the listener', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - const onClick = () => {}; - - const marker = new HTMLMarker(params); - - const removeEventListener = jest.spyOn( - marker.element, - 'removeEventListener' - ); - - const subscription = marker.addListener('click', onClick); - - subscription.remove(); - - expect(removeEventListener).toHaveBeenCalledTimes(1); - expect(removeEventListener).toHaveBeenCalledWith('click', onClick); - expect(marker.subscriptions).toHaveLength(0); - }); - }); - - describe('getPosition', () => { - it('expect to return the latLng', () => { - const googleReference = createFakeGoogleReference(); - const HTMLMarker = createHTMLMarker(googleReference); - const params = createFakeParams(); - - const marker = new HTMLMarker(params); - - const actual = marker.getPosition(); - const expectation = { lat: 10, lng: 12 }; - - expect(actual).toEqual(expectation); - }); - }); -}); diff --git a/packages/react-instantsearch-dom-maps/src/elements/createHTMLMarker.js b/packages/react-instantsearch-dom-maps/src/elements/createHTMLMarker.js deleted file mode 100644 index 5d091d5cbd..0000000000 --- a/packages/react-instantsearch-dom-maps/src/elements/createHTMLMarker.js +++ /dev/null @@ -1,88 +0,0 @@ -const createHTMLMarker = (google) => { - class HTMLMarker extends google.maps.OverlayView { - constructor({ - position, - map, - className, - anchor = { - x: 0, - y: 0, - }, - }) { - super(); - - this.anchor = anchor; - this.subscriptions = []; - this.latLng = new google.maps.LatLng(position); - - this.element = document.createElement('div'); - this.element.className = className; - this.element.style.position = 'absolute'; - // Force the "white-space" of the element will avoid the - // content to collapse when we move the map from center - this.element.style.whiteSpace = 'nowrap'; - - this.setMap(map); - } - - onAdd() { - if (this.getPanes()) { - this.getPanes().overlayMouseTarget.appendChild(this.element); - } - } - - draw() { - if (this.getProjection()) { - const position = this.getProjection().fromLatLngToDivPixel(this.latLng); - - const offsetX = this.anchor.x + this.element.offsetWidth / 2; - const offsetY = this.anchor.y + this.element.offsetHeight; - - this.element.style.left = `${Math.round(position.x - offsetX)}px`; - this.element.style.top = `${Math.round(position.y - offsetY)}px`; - - // Markers to the south are in front of markers to the north - // This is the default behaviour of Google Maps - this.element.style.zIndex = parseInt(this.element.style.top, 10); - } - } - - onRemove() { - if (this.element && this.element.parentNode) { - this.element.parentNode.removeChild(this.element); - - this.subscriptions.forEach((subscription) => subscription.remove()); - - delete this.element; - - this.subscriptions = []; - } - } - - addListener(eventName, listener) { - const subscription = { - remove: () => { - this.element.removeEventListener(eventName, listener); - - this.subscriptions = this.subscriptions.filter( - (_) => _ !== subscription - ); - }, - }; - - this.element.addEventListener(eventName, listener); - - this.subscriptions = this.subscriptions.concat(subscription); - - return subscription; - } - - getPosition() { - return this.latLng; - } - } - - return HTMLMarker; -}; - -export default createHTMLMarker; diff --git a/packages/react-instantsearch-dom-maps/src/index.js b/packages/react-instantsearch-dom-maps/src/index.js deleted file mode 100644 index 9e130489dc..0000000000 --- a/packages/react-instantsearch-dom-maps/src/index.js +++ /dev/null @@ -1,8 +0,0 @@ -export { default as GeoSearch } from './GeoSearch'; -export { default as Marker } from './Marker'; -export { default as CustomMarker } from './CustomMarker'; -export { default as Redo } from './Redo'; -export { default as Control } from './Control'; -export { default as GeoSearchContext } from './GeoSearchContext'; -export { default as GoogleMapsLoader } from './GoogleMapsLoader'; -export { default as withGoogleMaps } from './withGoogleMaps'; diff --git a/packages/react-instantsearch-dom-maps/src/propTypes.js b/packages/react-instantsearch-dom-maps/src/propTypes.js deleted file mode 100644 index cb0ac58e08..0000000000 --- a/packages/react-instantsearch-dom-maps/src/propTypes.js +++ /dev/null @@ -1,15 +0,0 @@ -import PropTypes from 'prop-types'; - -export const LatLngPropType = PropTypes.shape({ - lat: PropTypes.number.isRequired, - lng: PropTypes.number.isRequired, -}); - -export const BoundingBoxPropType = PropTypes.shape({ - northEast: LatLngPropType.isRequired, - southWest: LatLngPropType.isRequired, -}); - -export const GeolocHitPropType = PropTypes.shape({ - _geoloc: LatLngPropType.isRequired, -}); diff --git a/packages/react-instantsearch-dom-maps/src/utils.js b/packages/react-instantsearch-dom-maps/src/utils.js deleted file mode 100644 index bd20e19e7c..0000000000 --- a/packages/react-instantsearch-dom-maps/src/utils.js +++ /dev/null @@ -1,33 +0,0 @@ -import PropTypes from 'prop-types'; - -export const registerEvents = (events, props, instance) => { - const eventsAvailable = Object.keys(events); - const listeners = Object.keys(props) - .filter((key) => eventsAvailable.indexOf(key) !== -1) - .map((name) => - instance.addListener(events[name], (event) => { - props[name]({ event, marker: instance }); - }) - ); - - return () => { - listeners.forEach((listener) => listener.remove()); - }; -}; - -export const createListenersPropTypes = (eventTypes) => - Object.keys(eventTypes).reduce( - (acc, name) => ({ ...acc, [name]: PropTypes.func }), - {} - ); - -export const createFilterProps = (excludes) => (props) => - Object.keys(props) - .filter((name) => excludes.indexOf(name) === -1) - .reduce( - (acc, name) => ({ - ...acc, - [name]: props[name], - }), - {} - ); diff --git a/packages/react-instantsearch-dom-maps/src/withGoogleMaps.tsx b/packages/react-instantsearch-dom-maps/src/withGoogleMaps.tsx deleted file mode 100644 index 25579d4995..0000000000 --- a/packages/react-instantsearch-dom-maps/src/withGoogleMaps.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; - -import GoogleMapsContext from './GoogleMapsContext'; - -type Subtract = Omit< - TProps, - keyof TSubstractedProps ->; - -export interface WithGoogleMapsProps { - google: typeof google; - googleMapsInstance: google.maps.Map; -} - -const withGoogleMaps = ( - Wrapped: React.ComponentType -) => { - const WithGoogleMaps: React.FC> = ( - props - ) => ( - - {({ google, instance }) => ( - - )} - - ); - - return WithGoogleMaps; -}; - -export default withGoogleMaps; diff --git a/packages/react-instantsearch-dom-maps/test/mockGoogleMaps.js b/packages/react-instantsearch-dom-maps/test/mockGoogleMaps.js deleted file mode 100644 index 9e1f5fbf81..0000000000 --- a/packages/react-instantsearch-dom-maps/test/mockGoogleMaps.js +++ /dev/null @@ -1,89 +0,0 @@ -export class FakeOverlayView { - setMap = jest.fn(); - - getPanes = jest.fn(() => ({ - overlayMouseTarget: { - appendChild: jest.fn(), - }, - })); - - getProjection = jest.fn(() => ({ - fromLatLngToDivPixel: jest.fn(() => ({ - x: 0, - y: 0, - })), - })); -} - -export const MockLatLngBounds = jest.fn((ne, sw) => ({ - northEast: ne, - southWest: sw, - equals(oldBounds) { - if (!oldBounds) { - return false; - } - return ( - oldBounds.northEast.lat === this.northEast.lat && - oldBounds.northEast.lng === this.northEast.lng && - oldBounds.southWest.lat === this.southWest.lat && - oldBounds.southWest.lng === this.southWest.lng - ); - }, -})); - -export const createFakeMapInstance = () => ({ - addListener: jest.fn(() => ({ - remove: jest.fn(), - })), - getCenter: jest.fn(), - setCenter: jest.fn(), - getZoom: jest.fn(), - setZoom: jest.fn(), - getBounds: jest.fn( - () => new MockLatLngBounds({ lat: 0, lng: 0 }, { lat: 0, lng: 0 }) - ), - getProjection: jest.fn(() => ({ - fromPointToLatLng: jest.fn(() => ({ - lat: jest.fn(), - lng: jest.fn(), - })), - fromLatLngToPoint: jest.fn(() => ({ - x: 0, - y: 0, - })), - })), - fitBounds: jest.fn(), -}); - -export const createFakeMarkerInstance = () => ({ - setMap: jest.fn(), - getPosition: jest.fn(), - addListener: jest.fn(), -}); - -export const createFakeHTMLMarkerInstance = () => ({ - element: document.createElement('div'), - setMap: jest.fn(), - draw: jest.fn(), -}); - -export const createFakeGoogleReference = ({ - mapInstance = createFakeMapInstance(), - markerInstance = createFakeMarkerInstance(), -} = {}) => ({ - maps: { - LatLng: jest.fn((x) => x), - LatLngBounds: MockLatLngBounds, - Map: jest.fn(() => mapInstance), - Marker: jest.fn(() => markerInstance), - ControlPosition: { - LEFT_TOP: 'left:top', - }, - event: { - addListenerOnce: jest.fn(() => ({ - remove: jest.fn(), - })), - }, - OverlayView: FakeOverlayView, - }, -}); diff --git a/packages/react-instantsearch-dom/.storybook/addons.ts b/packages/react-instantsearch-dom/.storybook/addons.ts deleted file mode 100644 index b9991485de..0000000000 --- a/packages/react-instantsearch-dom/.storybook/addons.ts +++ /dev/null @@ -1,4 +0,0 @@ -import '@storybook/addon-knobs/register'; -import '@storybook/addon-actions/register'; -import '@storybook/addon-a11y/register'; -import '@storybook/addons'; diff --git a/packages/react-instantsearch-dom/.storybook/config.ts b/packages/react-instantsearch-dom/.storybook/config.ts deleted file mode 100644 index d214bdfdd5..0000000000 --- a/packages/react-instantsearch-dom/.storybook/config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { configure, addDecorator, addParameters } from '@storybook/react'; -import { withKnobs } from '@storybook/addon-knobs'; -import { withA11y } from '@storybook/addon-a11y'; -import { create } from '@storybook/theming'; - -addParameters({ - options: { - panelPosition: 'right', - theme: create({ - base: 'light', - brandTitle: 'react-instantsearch', - brandUrl: 'https://github.com/algolia/instantsearch.js', - }), - }, -}); - -addDecorator(withKnobs); -addDecorator(withA11y); - -const req = require.context('../stories', true, /\.stories\.(js|ts|tsx)$/); - -function loadStories() { - req.keys().forEach((filename) => req(filename)); -} - -configure(loadStories, module); diff --git a/packages/react-instantsearch-dom/.storybook/postcss.config.js b/packages/react-instantsearch-dom/.storybook/postcss.config.js deleted file mode 100644 index a47ef4f952..0000000000 --- a/packages/react-instantsearch-dom/.storybook/postcss.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - plugins: { - autoprefixer: {}, - }, -}; diff --git a/packages/react-instantsearch-dom/.storybook/preview-head.html b/packages/react-instantsearch-dom/.storybook/preview-head.html deleted file mode 100644 index 5c0ee00b70..0000000000 --- a/packages/react-instantsearch-dom/.storybook/preview-head.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/packages/react-instantsearch-dom/.storybook/public/default.css b/packages/react-instantsearch-dom/.storybook/public/default.css deleted file mode 100644 index 7713b5444d..0000000000 --- a/packages/react-instantsearch-dom/.storybook/public/default.css +++ /dev/null @@ -1,14 +0,0 @@ -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, - Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - font-size: 14px; -} - -a { - color: #3e82f7; - text-decoration: none; -} - -#root img { - max-width: 100%; -} diff --git a/packages/react-instantsearch-dom/.storybook/public/react-autosuggest.css b/packages/react-instantsearch-dom/.storybook/public/react-autosuggest.css deleted file mode 100644 index 07c4db77e1..0000000000 --- a/packages/react-instantsearch-dom/.storybook/public/react-autosuggest.css +++ /dev/null @@ -1,69 +0,0 @@ -.react-autosuggest__container { - position: relative; -} - -.react-autosuggest__input { - width: 400px; - height: 30px; - padding: 10px 20px; - font-family: Helvetica, sans-serif; - font-weight: 300; - font-size: 16px; - border: 1px solid #aaa; - border-radius: 4px; -} - -.react-autosuggest__input:focus { - outline: none; -} - -.react-autosuggest__container--open .react-autosuggest__input { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -.react-autosuggest__suggestions-container { - display: none; -} - -.react-autosuggest__container--open .react-autosuggest__suggestions-container { - display: block; - position: absolute; - top: 51px; - width: 520px; - border: 1px solid #aaa; - background-color: #fff; - font-family: Helvetica, sans-serif; - font-weight: 300; - font-size: 16px; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; - z-index: 2; -} - -.react-autosuggest__suggestions-list { - margin: 0; - padding: 0; - list-style-type: none; -} - -.react-autosuggest__suggestion { - cursor: pointer; - padding: 10px 20px; -} - -.react-autosuggest__suggestion--focused { - background-color: #ddd; -} - -.react-autosuggest__section-title { - padding: 10px 0 0 10px; - font-size: 12px; - text-transform: uppercase; - color: #777; - border-top: 1px dashed #ccc; -} - -.react-autosuggest__section-container:first-child .react-autosuggest__section-title { - border-top: 0; -} \ No newline at end of file diff --git a/packages/react-instantsearch-dom/.storybook/public/rheostat.css b/packages/react-instantsearch-dom/.storybook/public/rheostat.css deleted file mode 100644 index d2756cf848..0000000000 --- a/packages/react-instantsearch-dom/.storybook/public/rheostat.css +++ /dev/null @@ -1,46 +0,0 @@ -.rheostat { - height: 24px; - position: relative; - overflow: visible -} - -.rheostat-background { - background: #dce0e0; - height: 2px; - position: relative; - top: 14px; - width: 100% -} - -.rheostat--disabled .rheostat-progress { - background-color: #edefed -} - -.rheostat--disabled .rheostat-handle { - cursor: default -} - -.rheostat-progress { - background-color: #3369e7; - height: 4px; - position: absolute; - top: 13px -} - -.rheostat-handle { - border: 1px solid #aaa; - background: #fff; - -webkit-border-radius: 100%; - -moz-border-radius: 100%; - border-radius: 100%; - -webkit-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - -moz-box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); - cursor: pointer; - height: 24px; - margin-left: -12px; - position: absolute; - z-index: 2; - width: 24px; - font-size: 0 -} \ No newline at end of file diff --git a/packages/react-instantsearch-dom/.storybook/public/util.css b/packages/react-instantsearch-dom/.storybook/public/util.css deleted file mode 100644 index 09682fb4e2..0000000000 --- a/packages/react-instantsearch-dom/.storybook/public/util.css +++ /dev/null @@ -1,272 +0,0 @@ -/** - * Container - */ - -.container { - padding: 50px 40px 40px; - position: relative; - overflow-x: hidden; - clear: left; -} - -.container:after { - font-size: 13px; - top: 0; - left: 0; - color: #999999; - padding: 4px 6px; - line-height: 1em; - position: absolute; - background-color: #f3f3f3; - border: solid 1px #e4e4e4; - border-width: 0 1px 1px 0; -} - -.footer-container { - border-radius: 0px 0px 5px 5px; - display: flex; - justify-content: space-around; - overflow-x: hidden; - clear: left; - border-bottom: solid 1px #e4e4e4; - border-left: solid 1px #e4e4e4; - border-right: solid 1px #e4e4e4; - background-color: #f3f3f3; -} - -.playground-url, -.source-code-url { - font-family: inherit; - font-size: 13px; - top: 0; - left: 0; - color: #999999; - padding: 4px 6px; - line-height: 1em; - background-color: #f3f3f3; - border: none; -} - -/** - * Widget - */ - -.widget-container { - border: solid 1px #e4e4e4; - border-radius: 5px 5px 0px 0px; -} - -.widget-container:after { - content: 'Widget display'; - border-radius: 5px 0 3px; -} - -/** - * Results - */ - -.hits-container { - border-left: solid 1px #e4e4e4; - border-right: solid 1px #e4e4e4; - border-bottom: solid 1px #e4e4e4; - display: flex; - flex-direction: column; -} - -.hits-container:after { - content: 'Results'; -} - -/** - * Search - */ - -.hit-actions { - display: flex; - align-items: center; -} - -.hit-actions > .ais-ClearRefinements { - margin-left: 15px; -} - -/** - * Hits - */ - -.hits { - margin: 25px 0; -} - -.hit { - padding: 5px 5px; - display: flex; - align-items: center; -} - -.hit--airbnb:hover, -.hit--airbnb-active { - background-color: #3369e7; - color: #ffffff; -} - -.ais-SearchBox__root { - margin-right: 10px; -} - -.hit-content { - margin-left: 20px; -} - -.hit-picture > img { - width: 80px; - height: 80px; -} - -.hit-type { - color: #888888; - font-size: 13px; -} - -/** - * Multi-index - */ - -.multi-index_content { - display: flex; - flex-direction: column; - margin-top: 10px; -} - -.multi-index_hit { - padding: 10px; -} - -.multi-index_hit { - display: flex; -} - -.multi-index_hit .multi-index_hit-content { - padding-left: 10px; -} - -/* GeoSearch */ - -.my-custom-marker { - position: relative; - background-color: white; - border: 1px solid rgba(0, 0, 0, 0.2); - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, - Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; - font-weight: 500; - font-size: 1rem; - padding: 3px 5px; - box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.15); -} - -.my-custom-marker:hover, -.my-custom-marker--active { - background-color: #3369e7; - color: white; - cursor: pointer; -} - -.my-custom-marker::after { - content: ''; - display: block; - position: absolute; - width: 8px; - height: 8px; - bottom: -5px; - background-color: white; - border-color: rgba(0, 0, 0, 0.2); - border-width: 0 1px 1px 0; - border-style: solid; - left: 50%; - margin-left: -4px; - transform: rotate(45deg); -} - -.my-custom-marker:hover::after, -.my-custom-marker--active::after { - background-color: #3369e7; -} - -/* Voice Search */ -.custom-button-story .ais-VoiceSearch-button:hover { - background: inherit; -} - -.custom-ui .ais-VoiceSearch-button { - position: absolute; - right: 43px; - top: 53px; - z-index: 3; -} -.custom-ui .ais-VoiceSearch-status .layer { - position: absolute; - background: rgba(255, 255, 255, 0.95); - top: 0; - bottom: 0; - left: 0; - right: 0; - z-index: 2; - align-items: center; - justify-content: center; - display: none; -} -.custom-ui .ais-VoiceSearch-status .layer.listening-true { - display: flex; -} -.custom-ui .ais-VoiceSearch-status .layer span { - font-size: 2rem; - color: #555; -} - -/* Related items */ - -.related-items { - display: flex; - align-items: center; -} - -.related-items .ais-Hits-list { - margin-left: 0; - margin-right: 1rem; -} - -.ais-RelatedHits-item-image { - height: 150px; - display: flex; - justify-content: center; - align-items: center; - padding: 1rem; - background-color: #fff; -} - -.ais-RelatedHits-item-image img { - max-height: 120px; -} - -.ais-RelatedHits-item-title { - text-align: center; - padding: 1rem; -} - -.ais-RelatedHits-item-title h4 { - margin: 0; -} - -.ais-RelatedHits-button { - height: 40px; - width: 40px; - border-radius: 3px; - background-color: #dfe2ee; - border: none; - color: #3a4570; - cursor: pointer; -} - -.ais-RelatedHits-button[disabled] { - cursor: not-allowed; -} diff --git a/packages/react-instantsearch-dom/.storybook/webpack.config.js b/packages/react-instantsearch-dom/.storybook/webpack.config.js deleted file mode 100644 index dc0e83b4e6..0000000000 --- a/packages/react-instantsearch-dom/.storybook/webpack.config.js +++ /dev/null @@ -1,26 +0,0 @@ -module.exports = ({ config }) => ({ - ...config, - module: { - ...config.module, - rules: [ - { - test: /\.(js|ts|tsx)$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - options: { - rootMode: 'upward', - presets: [['react-app', { typescript: true }]], - exclude: /node_modules|algoliasearch-helper/, - }, - }, - ], - }, - { - test: /\.css$/, - use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], - }, - ], - }, -}); diff --git a/packages/react-instantsearch-dom/CHANGELOG.md b/packages/react-instantsearch-dom/CHANGELOG.md deleted file mode 100644 index d58649ba15..0000000000 --- a/packages/react-instantsearch-dom/CHANGELOG.md +++ /dev/null @@ -1,1891 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.40.4](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.40.3...react-instantsearch-dom@6.40.4) (2023-07-25) - -**Note:** Version bump only for package react-instantsearch-dom - - - - - -## [6.40.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.40.2...react-instantsearch-dom@6.40.3) (2023-07-19) - - -### Bug Fixes - -* **instantsearch:** keep algoliasearch-helper as external dependency during build ([#5765](https://github.com/algolia/instantsearch.js/issues/5765)) ([550fefa](https://github.com/algolia/instantsearch.js/commit/550fefa1401773f38dedc20322513ae662faa25d)) - - - - - -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.40.1...react-instantsearch-dom@6.40.2) (2023-07-18) - -**Note:** Version bump only for package react-instantsearch-dom - - - - - -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.40.0...react-instantsearch-dom@6.40.1) (2023-06-20) - - -### Bug Fixes - -* **dependencies:** update helper requirement ([#5676](https://github.com/algolia/instantsearch.js/issues/5676)) ([c289120](https://github.com/algolia/instantsearch.js/commit/c2891205c1125b1203b3b3db946d57e0fc4e4687)), closes [#5658](https://github.com/algolia/instantsearch.js/issues/5658) - - - - - -# [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.39.1...react-instantsearch-dom@6.40.0) (2023-05-16) - - -### Bug Fixes - -* **this:** ensure all functions are able to be destructured ([#5611](https://github.com/algolia/instantsearch.js/issues/5611)) ([a8b5c1e](https://github.com/algolia/instantsearch.js/commit/a8b5c1e5bbd6afac39fce523f7d7c2ec02f51153)), closes [#5589](https://github.com/algolia/instantsearch.js/issues/5589) - - -### Features - -* **instantsearch:** make root indexName optional ([#5590](https://github.com/algolia/instantsearch.js/issues/5590)) ([80f309e](https://github.com/algolia/instantsearch.js/commit/80f309ed69b61534ca118b60c9c88691e0148fca)) - - - - - -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.39.0...react-instantsearch-dom@6.39.1) (2023-03-21) - - -### Bug Fixes - -* **searchbox:** add aria-hidden to svg icons ([#5547](https://github.com/algolia/instantsearch.js/issues/5547)) ([50344e3](https://github.com/algolia/instantsearch.js/commit/50344e3b14c22c886415c0e7d799aca778dc39ab)), closes [#5546](https://github.com/algolia/instantsearch.js/issues/5546) - - - - - -# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.38.3...react-instantsearch-dom@6.39.0) (2023-01-26) - - -### Bug Fixes - -* **dependencies:** update typescript ([#5454](https://github.com/algolia/instantsearch.js/issues/5454)) ([0e6bb48](https://github.com/algolia/instantsearch.js/commit/0e6bb485a31cd3294436ac9902c2c2662dfcdf8b)) - - -### Features - -* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) - - - - - - -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.38.2...react-instantsearch-dom@6.38.3) (2023-01-09) - - -### Bug Fixes - -* **dependencies:** update helper requirement for minor PP vulnerability ([#5417](https://github.com/algolia/instantsearch.js/issues/5417)) ([254ef00](https://github.com/algolia/instantsearch.js/commit/254ef00439a9af48be15f22b4fd9902899610226)) - - - - - -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-dom@6.38.1...react-instantsearch-dom@6.38.2) (2023-01-03) - -**Note:** Version bump only for package react-instantsearch-dom - - - - - -## [6.38.1](https://github.com/algolia/react-instantsearch/compare/v6.38.0...v6.38.1) (2022-11-08) - - -### Bug Fixes - -* **hooks:** avoid effect in useStableValue ([#3670](https://github.com/algolia/react-instantsearch/issues/3670)) ([d1f53ae](https://github.com/algolia/react-instantsearch/commit/d1f53ae815b75f13c18fd245e0403d57e7ae391c)) - - - -# [6.38.0](https://github.com/algolia/react-instantsearch/compare/v6.37.0...v6.38.0) (2022-10-25) - - -### Features - -* **getServerState:** allow users to inject renderToString ([#3658](https://github.com/algolia/react-instantsearch/issues/3658)) ([9c10449](https://github.com/algolia/react-instantsearch/commit/9c104497b9b32337f288d70a2582c41cafb13cd6)), closes [#3633](https://github.com/algolia/react-instantsearch/issues/3633) [#3618](https://github.com/algolia/react-instantsearch/issues/3618) [vercel/next.js#40067](https://github.com/vercel/next.js/issues/40067) - -* **PoweredBy:** update component logo ([#3661](https://github.com/algolia/react-instantsearch/issues/3661)) ([69c1b2a](https://github.com/algolia/react-instantsearch/commit/69c1b2acef64d972dfa6c6beb8967032119ad2d5)) - - - -# [6.37.0](https://github.com/algolia/react-instantsearch/compare/v6.36.0...v6.37.0) (2022-10-18) - - -### Features - -* **core:** support react 18 strict mode ([#3653](https://github.com/algolia/react-instantsearch/issues/3653)) ([9174806](https://github.com/algolia/react-instantsearch/commit/9174806a7997a45893a24d149027119f4a0709c3)) - - - -# [6.36.0](https://github.com/algolia/react-instantsearch/compare/v6.35.0...v6.36.0) (2022-10-04) - - -### Features - -* **HierarchicalMenu:** add css class for link of selected menu item ([#3646](https://github.com/algolia/react-instantsearch/issues/3646)) ([980ad70](https://github.com/algolia/react-instantsearch/commit/980ad70c75e970c35c11a10a534dbe3996d6c54c)) -* **useInstantSearch:** expose status & error ([#3645](https://github.com/algolia/react-instantsearch/issues/3645)) ([f436d31](https://github.com/algolia/react-instantsearch/commit/f436d31184f3f75b33a1fdaa19c665e77948df28)) - - - -# [6.35.0](https://github.com/algolia/react-instantsearch/compare/v6.34.0...v6.35.0) (2022-09-29) - - -### Features - -* **hooks-web:** introduce Translations API ([#3638](https://github.com/algolia/react-instantsearch/issues/3638)) ([63b506f](https://github.com/algolia/react-instantsearch/commit/63b506f9dbad284f45ac17210e17c4a2a8f099b6)) - -### Fixes -* **hooks-web:** when searchAsYouType=false, pressing the reset button searches (previously only reset the query) ([#3642](https://github.com/algolia/react-instantsearch/issues/3642)) ([f969deb](https://github.com/algolia/react-instantsearch/commit/f969deb05fd4f53aaa251ff88b52db2224ce0786)) - -# [6.34.0](https://github.com/algolia/react-instantsearch/compare/v6.33.0...v6.34.0) (2022-09-27) - - -### Features - -* **SearchBox:** expose formRef ([#3565](https://github.com/algolia/react-instantsearch/issues/3565)) ([1c2f46d](https://github.com/algolia/react-instantsearch/commit/1c2f46da2d1cf705cfd3946c52aef4ca9ec943d7)) - - - -# [6.33.0](https://github.com/algolia/react-instantsearch/compare/v6.32.1...v6.33.0) (2022-09-15) - - -### Bug Fixes - -* **react-native:** mark as compatible with react 18 ([#3614](https://github.com/algolia/react-instantsearch/issues/3614)) ([2a191a8](https://github.com/algolia/react-instantsearch/commit/2a191a84751127de5a3eb34b59b460a1d1bfe594)) -* **rish:** hide reset button when search is stalled in `SearchBox` ([#3617](https://github.com/algolia/react-instantsearch/issues/3617)) ([93ee9d0](https://github.com/algolia/react-instantsearch/commit/93ee9d0212893cef4842c86b7c78f285aa136be8)) - - -### Features - -* **dependencies:** update instantsearch and helper ([#3622](https://github.com/algolia/react-instantsearch/issues/3622)) ([6773ab1](https://github.com/algolia/react-instantsearch/commit/6773ab169cd74dfe1133e255daade4d57e99d9a4)) - - - -## [6.32.1](https://github.com/algolia/react-instantsearch/compare/v6.32.0...v6.32.1) (2022-08-26) - - -### Bug Fixes - -* **useInstantSearch:** prevent `results` from being `null` when first search is stalled ([#3597](https://github.com/algolia/react-instantsearch/issues/3597)) ([6f71d78](https://github.com/algolia/react-instantsearch/commit/6f71d78868fde55a3f9c4460edc337a1e99df4f9)) - - - -# [6.32.0](https://github.com/algolia/react-instantsearch/compare/v6.31.1...v6.32.0) (2022-08-22) - - -### Features - -* **SearchBox:** introduce `autoFocus` prop ([#3599](https://github.com/algolia/react-instantsearch/issues/3599)) ([99121b9](https://github.com/algolia/react-instantsearch/commit/99121b952fd002cb6dae52af41f08beed8f6c3e2)) - - - -## [6.31.1](https://github.com/algolia/react-instantsearch/compare/v6.31.0...v6.31.1) (2022-08-08) - - -### Bug Fixes - -* **hooks:** prevent widget cleanup on `` unmount ([#3590](https://github.com/algolia/react-instantsearch/issues/3590)) ([d94899d](https://github.com/algolia/react-instantsearch/commit/d94899d1264134f0cb1ca2d266a660f1fb2a588c)) - - - -# [6.31.0](https://github.com/algolia/react-instantsearch/compare/v6.30.3...v6.31.0) (2022-08-03) - - -### Features - -* **hooks:** add `searchAsYouType` option to `` ([#3585](https://github.com/algolia/react-instantsearch/issues/3585)) ([c610385](https://github.com/algolia/react-instantsearch/commit/c610385cb9688b23b3e041e31b9edd60392b341d)) - - - -## [6.30.3](https://github.com/algolia/react-instantsearch/compare/v6.30.2...v6.30.3) (2022-08-01) - - -### Bug Fixes - -* **hooks:** replace `labelText` CSS class with `label` in `` to align with InstantSearch's CSS specifications ([#3583](https://github.com/algolia/react-instantsearch/issues/3583)) ([3e030ae](https://github.com/algolia/react-instantsearch/commit/3e030aedb9f285ff449eb82589bc6fea60b160cb)) - - - -## [6.30.2](https://github.com/algolia/react-instantsearch/compare/v6.30.1...v6.30.2) (2022-07-18) - - -### Bug Fixes - -* **hooks:** type of DynamicWidgets props ([#3566](https://github.com/algolia/react-instantsearch/issues/3566)) ([612c98b](https://github.com/algolia/react-instantsearch/commit/612c98b5a77fb9037185c4b5efda8c07663dbd1a)), closes [#3563](https://github.com/algolia/react-instantsearch/issues/3563) -* **hooks:** use single instance in ([#3561](https://github.com/algolia/react-instantsearch/issues/3561)) ([4c358be](https://github.com/algolia/react-instantsearch/commit/4c358bebfc91451b1610f677f89c595d7a427f1f)) - - - -## [6.30.1](https://github.com/algolia/react-instantsearch/compare/v6.30.0...v6.30.1) (2022-07-12) - - -### Bug Fixes - -* **hooks:** provide state and results APIs from "render" event ([#3554](https://github.com/algolia/react-instantsearch/issues/3554)) ([67d4788](https://github.com/algolia/react-instantsearch/commit/67d4788ab09ec2a57b43d53e8093b8c11120b761)) -* **hooks**: update instantsearch.js dependency ([#3557](https://github.com/algolia/react-instantsearch/issues/3557)) - - - -# [6.30.0](https://github.com/algolia/react-instantsearch/compare/v6.29.0...v6.30.0) (2022-07-05) - - -### Features - -* **core:** update instantsearch and helper ([#3539](https://github.com/algolia/react-instantsearch/issues/3539)) ([0ac2c7a](https://github.com/algolia/react-instantsearch/commit/0ac2c7a3f2e2a827721f5b2b7c69c54560f8574f)) - - - -# [6.29.0](https://github.com/algolia/react-instantsearch/compare/v6.28.0...v6.29.0) (2022-06-21) - - -### Bug Fixes - -* **HierarchicalMenu:** show full hierarchical parent values ([#3521](https://github.com/algolia/react-instantsearch/issues/3521)) ([79c3890](https://github.com/algolia/react-instantsearch/commit/79c3890848175a4d70311e5c3929c902bb953c10)) - - -### Features - -* **core:** sort parameters for improved cache rate ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) -* **core:** support client.search for sffv ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) - - - -# [6.28.0](https://github.com/algolia/react-instantsearch/compare/v6.27.0...v6.28.0) (2022-06-15) - - -### Bug Fixes - -* **hooks-server:** import react server via an expression ([#3515](https://github.com/algolia/react-instantsearch/issues/3515)) ([91b96f7](https://github.com/algolia/react-instantsearch/commit/91b96f743b9315ed5ea781681b77fc7f5604ab6e)), closes [#3512](https://github.com/algolia/react-instantsearch/issues/3512) -* **hooks-web:** fix duplicated key in ([#3513](https://github.com/algolia/react-instantsearch/issues/3513)) ([fc94d80](https://github.com/algolia/react-instantsearch/commit/fc94d806daf139f58b234cdc0b450da2efe861ee)) -* **hooks:** mount widgets in SSR to retrieve HTML ([#3518](https://github.com/algolia/react-instantsearch/issues/3518)) ([aa5f9d8](https://github.com/algolia/react-instantsearch/commit/aa5f9d84ddb6e97d05e6ad1baf2c6caa23891281)) -* **types:** allow useInstantSearch to be generic ([#3508](https://github.com/algolia/react-instantsearch/issues/3508)) ([6807232](https://github.com/algolia/react-instantsearch/commit/68072324cf302801502a1b4c3d06703e57b55a97)), closes [algolia/instantsearch.js#5060](https://github.com/algolia/instantsearch.js/issues/5060) -* **types:** support React 18 types ([#3481](https://github.com/algolia/react-instantsearch/issues/3481)) ([74cf8cb](https://github.com/algolia/react-instantsearch/commit/74cf8cb9be8ff3d113b57a50e7083df0d1bc94f2)) - - -### Features - -* **hooks:** introduce `useInstantSearch()` ([#3494](https://github.com/algolia/react-instantsearch/issues/3494)) ([74d522c](https://github.com/algolia/react-instantsearch/commit/74d522c032326658f2a0b8f0001bd593e0085208)) -* **hooks:** support React 18 Strict Mode ([#3514](https://github.com/algolia/react-instantsearch/issues/3514)) ([eeb67c7](https://github.com/algolia/react-instantsearch/commit/eeb67c7b5dc08c696c46d9538f104eeceecef388)) - - - -# [6.27.0](https://github.com/algolia/react-instantsearch/compare/v6.26.0...v6.27.0) (2022-06-07) - - -### Bug Fixes - -* **hooks-web:** don't pass widget props to ui components ([#3501](https://github.com/algolia/react-instantsearch/issues/3501)) ([5bd53c1](https://github.com/algolia/react-instantsearch/commit/5bd53c128ddeeea87f75ae89eb8f2324d476c70e)), closes [#3499](https://github.com/algolia/react-instantsearch/issues/3499) -* **SearchBox-hooks:** correctly pass widget props ([#3499](https://github.com/algolia/react-instantsearch/issues/3499)) ([2cdf906](https://github.com/algolia/react-instantsearch/commit/2cdf90602b7c2c5895124ef64c389ce574154386)), closes [#3498](https://github.com/algolia/react-instantsearch/issues/3498) - - -### Features - -* **hooks:** migrate to `useSyncExternalStore()` ([#3489](https://github.com/algolia/react-instantsearch/issues/3489)) ([81bbdf2](https://github.com/algolia/react-instantsearch/commit/81bbdf28f2d28d8b0081cfd7d9e84c3e33038dd2)) -* **hooks:** upgrade to InstantSearch.js 4.41.0 ([#3502](https://github.com/algolia/react-instantsearch/issues/3502)) ([0b76792](https://github.com/algolia/react-instantsearch/commit/0b76792ea0c4e2ac9fe742810d70ba1aee2a3e79)) - - - -# [6.26.0](https://github.com/algolia/react-instantsearch/compare/v6.25.0...v6.26.0) (2022-05-19) - - -### Features - -* **hooks-web:** expose `sendEvent` to `hitComponent` ([#3476](https://github.com/algolia/react-instantsearch/issues/3476)) ([5cc18d1](https://github.com/algolia/react-instantsearch/commit/5cc18d19d9f22305f33d92e43fd0aca2a5cb949a)) -* **react-instantsearch-core:** allow widgets to set their `$$widgetType` ([#3472](https://github.com/algolia/react-instantsearch/issues/3472)) ([1c436e1](https://github.com/algolia/react-instantsearch/commit/1c436e1429ab4230bbfea7c6d2474d141f5c5c64)) - - - -# [6.25.0](https://github.com/algolia/react-instantsearch/compare/v6.24.3...v6.25.0) (2022-05-17) - - -### Bug Fixes - -* **hooks-highlight:** make sure highlight and snippet don't show html-escaped content ([#3471](https://github.com/algolia/react-instantsearch/issues/3471)) ([c18ddd2](https://github.com/algolia/react-instantsearch/commit/c18ddd25faca37d6bfa3d1c28f6fc22ec5fcf6d8)) -* **hooks-server:** remove faulty UMD build ([#3465](https://github.com/algolia/react-instantsearch/issues/3465)) ([c1ddfe4](https://github.com/algolia/react-instantsearch/commit/c1ddfe408b411551ac8524877a9d65ded8133c42)) - - -### Features - -* **dom-maps:** expose GeoSearchContext ([#3468](https://github.com/algolia/react-instantsearch/issues/3468)) ([a61ff96](https://github.com/algolia/react-instantsearch/commit/a61ff96222bfd4f6301cf93bf95e2fa18b263d3c)), closes [#3448](https://github.com/algolia/react-instantsearch/issues/3448) -* **hooks-server:** support import from React 18 ([#3464](https://github.com/algolia/react-instantsearch/issues/3464)) ([0a13867](https://github.com/algolia/react-instantsearch/commit/0a13867f7dd5a8a18e0957b2072bbde3b02d6490)), closes [#3453](https://github.com/algolia/react-instantsearch/issues/3453) -* **hooks:** make InstantSearch type generic ([#3466](https://github.com/algolia/react-instantsearch/issues/3466)) ([b0905b7](https://github.com/algolia/react-instantsearch/commit/b0905b73bed558c62eedb7ae701be20c2ebe25c9)) - - - -## [6.24.3](https://github.com/algolia/react-instantsearch/compare/v6.24.2...v6.24.3) (2022-05-10) - - -### Bug Fixes - -* **numericmenu:** include range values in comparison with minmax bounds ([#3461](https://github.com/algolia/react-instantsearch/issues/3461)) ([e4c2682](https://github.com/algolia/react-instantsearch/commit/e4c268261dc42a6aa43d985934b53c82f8b71089)) - - - -## [6.24.2](https://github.com/algolia/react-instantsearch/compare/v6.24.1...v6.24.2) (2022-05-05) - - -### Bug Fixes - -* **hooks:** prevent infinite loops from render state ([#3455](https://github.com/algolia/react-instantsearch/issues/3455)) ([1799fc9](https://github.com/algolia/react-instantsearch/commit/1799fc9f78a4a5aafb54df339c3e211ff9187748)) - - - -## [6.24.1](https://github.com/algolia/react-instantsearch/compare/v6.24.0...v6.24.1) (2022-05-03) - - -### Bug Fixes - -* **types:** export correct types for react-instantsearch-hooks-web ([#3454](https://github.com/algolia/react-instantsearch/issues/3454)) ([a863430](https://github.com/algolia/react-instantsearch/commit/a8634306621f7a05a2b3056a6db25ccf8d9eabf0)) - - - -# [6.24.0](https://github.com/algolia/react-instantsearch/compare/v6.23.4...v6.24.0) (2022-04-28) - - -### Features - -* **hooks:** expose DOM components ([#3450](https://github.com/algolia/react-instantsearch/issues/3450)) ([5732e3d](https://github.com/algolia/react-instantsearch/commit/5732e3de732275911f94b26ba9e2c4165bdf77e7)) -* **hooks:** remove experimental warning ([#3446](https://github.com/algolia/react-instantsearch/issues/3446)) ([84c99fe](https://github.com/algolia/react-instantsearch/commit/84c99fe91d6906a877bec620b44c61d762f0ea57)) - - - -## [6.23.4](https://github.com/algolia/react-instantsearch/compare/v6.23.3...v6.23.4) (2022-04-21) - - -### Bug Fixes - -* **hooks:** forbid importing from instantsearch.js root path ([#3437](https://github.com/algolia/react-instantsearch/issues/3437)) ([82ef9ea](https://github.com/algolia/react-instantsearch/commit/82ef9eaaec42bc54f15796b5b031a8656330a45c)) -* **packages:** correctly mark peer dependency ([#3439](https://github.com/algolia/react-instantsearch/issues/3439)) ([51e8818](https://github.com/algolia/react-instantsearch/commit/51e8818fce224819230c8bf6dea2a08d71d9be29)), closes [#3428](https://github.com/algolia/react-instantsearch/issues/3428) - - - -## [6.23.3](https://github.com/algolia/react-instantsearch/compare/v6.23.2...v6.23.3) (2022-04-05) - - -### Bug Fixes - -* **facets:** show raw value in currentRefinements ([#3420](https://github.com/algolia/react-instantsearch/issues/3420)) ([1199ce6](https://github.com/algolia/react-instantsearch/commit/1199ce6bd4152e4b54bd2ee0e1f0c9d81021c7d5)), closes [#3412](https://github.com/algolia/react-instantsearch/issues/3412) -* **multi-index:** correctly set `searching` prop in multi-index result states ([#3419](https://github.com/algolia/react-instantsearch/issues/3419)) ([7f8e97e](https://github.com/algolia/react-instantsearch/commit/7f8e97e31b3dd5e49d3febef673f41f7dfa6d45d)) - - - -## [6.23.2](https://github.com/algolia/react-instantsearch/compare/v6.23.1...v6.23.2) (2022-04-04) - - -### Bug Fixes - -* **refinements:** use escaped value for refining ([#3412](https://github.com/algolia/react-instantsearch/issues/3412)) ([f2f5f6c](https://github.com/algolia/react-instantsearch/commit/f2f5f6cbfaed48a5c494daeb8789e8deebc64293)) -* support React 18 as peer dependency ([#3411](https://github.com/algolia/react-instantsearch/issues/3411)) ([38eb5a6](https://github.com/algolia/react-instantsearch/commit/38eb5a6a8fe92cb763a25f452bea78b189a6a82a)) - - -## [6.23.1](https://algolia/compare/v6.23.0...v6.23.1) (2022-03-30) - - -### Bug Fixes - -* **hooks:** compute initial search parameters from widget ([#3399](https://algolia/issues/3399)) ([b4bd933](https://algolia/commits/b4bd93358598bdc77a1aa858252e6eee23441345)) - - - -# [6.23.0](https://algolia/compare/v6.22.0...v6.23.0) (2022-03-23) - - -### Bug Fixes - -* **ssr:** perform initial multi-index search using a single request ([#3385](https://algolia/issues/3385)) ([b96809e](https://algolia/commits/b96809e5748d298350890647956cb7adbbb55650)) - - -### Features - -* **hooks:** allow additional widget properties to be passed from hooks ([#3359](https://algolia/issues/3359)) ([a047be4](https://algolia/commits/a047be45c7fce7ee28f7d6f61d2fbfa79e3ed2d0)) -* **hooks:** allow useHits and useInfiniteHit to be generic ([#3364](https://algolia/issues/3364)) ([8e66ad3](https://algolia/commits/8e66ad3ad587197c4811c60a5cab475137ca5afb)) -* **hooks:** mark initial results as "artificial" ([#3384](https://algolia/issues/3384)) ([937efdc](https://algolia/commits/937efdc71bae1d99270f8ecb5c5c9c501b3d7769)) - - - -# [6.22.0](https://github.com/algolia/react-instantsearch/compare/v6.21.1...v6.22.0) (2022-02-01) - - -### Bug Fixes - -* **hooks:** enable pause on exceptions on warning ([#3283](https://github.com/algolia/react-instantsearch/issues/3283)) ([ce3a6c3](https://github.com/algolia/react-instantsearch/commit/ce3a6c3f2700a05ae54a91278fd23fa64a97d733)) - - -### Features - -* **hooks:** introduce `useBreadcrumb()` ([#3245](https://github.com/algolia/react-instantsearch/issues/3245)) ([5bfbaaf](https://github.com/algolia/react-instantsearch/commit/5bfbaaf746e7632968ac9b30b73357bcb0b37e91)) - - - -## [6.21.1](https://github.com/algolia/react-instantsearch/compare/v6.21.0...v6.21.1) (2022-01-25) - - -### Bug Fixes - -* **hooks:** apply initial search parameters in useConnector ([#3276](https://github.com/algolia/react-instantsearch/issues/3276)) ([f85d679](https://github.com/algolia/react-instantsearch/commit/f85d6794c31eac61521fd8fc16b75673f02ed75b)) - - - -# [6.21.0](https://github.com/algolia/react-instantsearch/compare/v6.20.0...v6.21.0) (2022-01-24) - - -### Features - -* **hooks-server:** load data twice in the case of dynamic widget usage ([#3259](https://github.com/algolia/react-instantsearch/issues/3259)) ([9b4903b](https://github.com/algolia/react-instantsearch/commit/9b4903b2ea73d9d7e33729b87d9d55990e64312c)) -* **server:** load data twice in the case of dynamic widget usage ([#3268](https://github.com/algolia/react-instantsearch/issues/3268)) ([91cd085](https://github.com/algolia/react-instantsearch/commit/91cd085f9a323ed6b872f3a098f561007a72d0d2)), closes [/github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js#L14-L16](https://github.com//github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js/issues/L14-L16) - - - -# [6.20.0](https://github.com/algolia/react-instantsearch/compare/v6.19.0...v6.20.0) (2022-01-18) - - -### Bug Fixes - -* **hooks:** allow importing via require ([#3257](https://github.com/algolia/react-instantsearch/issues/3257)) ([6aa80b3](https://github.com/algolia/react-instantsearch/commit/6aa80b3647567199c3df1b90a07d708b223ce1fd)) - - -### Features - -* **hooks:** implement `useClearRefinements()` ([#3256](https://github.com/algolia/react-instantsearch/issues/3256)) ([930b83d](https://github.com/algolia/react-instantsearch/commit/930b83df4c4bbccbc3118f6ea1001f6a30a3d464)), closes [#3252](https://github.com/algolia/react-instantsearch/issues/3252) -* **hooks:** introduce `` ([#3261](https://github.com/algolia/react-instantsearch/issues/3261)) ([3527b94](https://github.com/algolia/react-instantsearch/commit/3527b9422de48a4a6b4bd752bd643e01cd5011d8)) -* **hooks:** introduce `usePoweredBy()` ([#3251](https://github.com/algolia/react-instantsearch/issues/3251)) ([a97230b](https://github.com/algolia/react-instantsearch/commit/a97230b89e3ba1df9bf2d21a6a9f9a70b45f41b8)) -* **hooks:** introduce `useToggleRefinement()` ([#3248](https://github.com/algolia/react-instantsearch/issues/3248)) ([a561c09](https://github.com/algolia/react-instantsearch/commit/a561c090a268e1c6ca1fa2d5bf72263cc47aa273)) - - - -# [6.19.0](https://github.com/algolia/react-instantsearch/compare/v6.18.0...v6.19.0) (2022-01-05) - - -### Features - -* **hooks:** bundle as es-module ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) -* **dependencies:** update to latest algoliasearch-helper ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) - - - -# [6.18.0](https://github.com/algolia/react-instantsearch/compare/v6.17.0...v6.18.0) (2021-12-16) - - -### Features - -* **dynamicWidgets:** send facets * and maxValuesPerFacet by default ([#3242](https://github.com/algolia/react-instantsearch/issues/3242)) ([c071776](https://github.com/algolia/react-instantsearch/commit/c07177670ac30dced55250774654e8b2a77b6739)) -* **hooks:** introduce `useNumericMenu()` ([#3237](https://github.com/algolia/react-instantsearch/issues/3237)) ([e3056c9](https://github.com/algolia/react-instantsearch/commit/e3056c9e2c64b5afafb7a736599a5cbf6137575b)) -* **hooks:** introduce `useInfiniteHits()` ([#3224](https://github.com/algolia/react-instantsearch/issues/3224)) ([177ec56](https://github.com/algolia/react-instantsearch/commit/177ec56af274670c2bf8599ba104b5544979bbe8)) - - - -# [6.17.0](https://github.com/algolia/react-instantsearch/compare/v6.16.0...v6.17.0) (2021-12-08) - - -### Bug Fixes - -* **hooks:** throw invariant violations in production ([#3217](https://github.com/algolia/react-instantsearch/issues/3217)) ([6d3f99c](https://github.com/algolia/react-instantsearch/commit/6d3f99ca91f470ee742ddc55e95f57b1f1801d7b)) - - -### Features - -* **hooks:** introduce `useMenu()` ([#3197](https://github.com/algolia/react-instantsearch/issues/3197)) ([15d1cc9](https://github.com/algolia/react-instantsearch/commit/15d1cc993437b111cd5a32f43ee1d2065c639ed4)) -* **hooks:** introduce `useRange()` ([#3198](https://github.com/algolia/react-instantsearch/issues/3198)) ([df1f1c8](https://github.com/algolia/react-instantsearch/commit/df1f1c8109dc684e74d3aee1bf0359f2a0e1b9f4)) -* **hooks:** introduce `` ([#3216](https://github.com/algolia/react-instantsearch/issues/3216)) ([d99aea6](https://github.com/algolia/react-instantsearch/commit/d99aea6cfe9dea86ae6b98ee3762373f4b3843f1)) -* **hooks:** introduce `useDynamicWidgets()` ([#3210](https://github.com/algolia/react-instantsearch/issues/3210)) ([29c2ea2](https://github.com/algolia/react-instantsearch/commit/29c2ea22b91a39d9eb40a044ae9aab85f2612db8)) -* **hooks:** introduce `useQueryRules()` ([#3212](https://github.com/algolia/react-instantsearch/issues/3212)) ([3ef1e1e](https://github.com/algolia/react-instantsearch/commit/3ef1e1e4116b3e58b2c2134d0c60fbb9f40c1501)) -* **hooks:** introduce SSR support ([#3221](https://github.com/algolia/react-instantsearch/issues/3221)) ([0a6b3ec](https://github.com/algolia/react-instantsearch/commit/0a6b3ec61942ad3849c6f078e21b3328679bffff)) -* **hooks:** introduce `useCurrentRefinements()` ([#3222](https://github.com/algolia/react-instantsearch/issues/3222)) ([7ebd8c3](https://github.com/algolia/react-instantsearch/commit/7ebd8c3da8c17b0bd7e0f8deab633b98fa052e7f)) - - - -# [6.16.0](https://github.com/algolia/react-instantsearch/compare/v6.15.0...v6.16.0) (2021-11-22) - - -### Bug Fixes - -* **PoweredBy:** support environments with `window` but no `location` ([#3186](https://github.com/algolia/react-instantsearch/issues/3186)) ([22ff23b](https://github.com/algolia/react-instantsearch/commit/22ff23b67554683567393114c2f53cacec44f4a6)) - - -### Features - -* **DynamicWidgets:** release as stable ([#3090](https://github.com/algolia/react-instantsearch/issues/3090)) ([a4a1d9e](https://github.com/algolia/react-instantsearch/commit/a4a1d9e032b31c611d5d73fdda3a03ad705f5c68)) -* **hooks:** introduce `usePagination()` ([#3182](https://github.com/algolia/react-instantsearch/issues/3182)) ([d8b1b86](https://github.com/algolia/react-instantsearch/commit/d8b1b867bb598e801f1350e81b4a4220a8e528d7)) -* **hooks:** introduce `useSortBy()` ([#3190](https://github.com/algolia/react-instantsearch/issues/3190)) ([5cce33b](https://github.com/algolia/react-instantsearch/commit/5cce33b48032548fed76b592ee0201e3c42fc3c4)) -* **hooks:** introduce `useHierarchicalMenu()` ([#3199](https://github.com/algolia/react-instantsearch/issues/3199)) ([b347061](https://github.com/algolia/react-instantsearch/commit/b3470611b962ef55c55576c65a6307abc54e5efd)) - - - -# [6.15.0](https://github.com/algolia/react-instantsearch/compare/v6.14.0...v6.15.0) (2021-10-27) - - -### Bug Fixes - -* **metadata:** stricter detection of user agent ([#3184](https://github.com/algolia/react-instantsearch/issues/3184)) ([994c8ae](https://github.com/algolia/react-instantsearch/commit/994c8ae055fc23a1a067d111d2f4727b1c7bf8ca)) - - -### Features - -* **hooks:** introduce `useConfigure()` ([#3181](https://github.com/algolia/react-instantsearch/issues/3181)) ([aa2eb9b](https://github.com/algolia/react-instantsearch/commit/aa2eb9baec6335f8a3523ee8b9b761a217cfc734)) - - - -# [6.14.0](https://github.com/algolia/react-instantsearch/compare/v6.13.0...v6.14.0) (2021-10-26) - - -### Features - -* **dependencies:** update algoliasearch-helper ([#3176](https://github.com/algolia/react-instantsearch/issues/3176)) ([a8708a3](https://github.com/algolia/react-instantsearch/commit/a8708a33f31632000bc827b076539b1cca7adf6f)) -* **metadata:** expose widget information ([#3145](https://github.com/algolia/react-instantsearch/issues/3145)) ([46cddf8](https://github.com/algolia/react-instantsearch/commit/46cddf8fcc0291beaa34b04da7aaaa7f2566e52e)) - - - -# [6.13.0](https://github.com/algolia/react-instantsearch/compare/v6.12.1...v6.13.0) (2021-10-19) - -This is the initial release of the experimental **React InstantSearch Hooks** package. Check out the [**Getting Started**](https://github.com/algolia/react-instantsearch/blob/e8d72cb1c7c45300ef7c273f1f163beb6dc57622/packages/react-instantsearch-hooks/README.md#getting-started) guide. - -### Bug Fixes - -- **core:** accept objects for `hitComponent` ([#3087](https://github.com/algolia/react-instantsearch/issues/3087)) ([4ae23d4](https://github.com/algolia/react-instantsearch/commit/4ae23d432a01ccbefff1fcdc865120aeca4d3efc)) - -### Features - -- **hooks:** add InstantSearch and Index components ([#3133](https://github.com/algolia/react-instantsearch/issues/3133)) ([8e3370d](https://github.com/algolia/react-instantsearch/commit/8e3370ddb7d5e42b8b9a5ff6a1e4255490de7dbe)) -- **hooks:** bootstrap Core package ([#3132](https://github.com/algolia/react-instantsearch/issues/3132)) ([d459e62](https://github.com/algolia/react-instantsearch/commit/d459e62f5cae4c98427ab302531873f5ee23d149)) -- **hooks:** display experimental warning ([#3149](https://github.com/algolia/react-instantsearch/issues/3149)) ([623577c](https://github.com/algolia/react-instantsearch/commit/623577c50cd0c04cd87f719edafdcfa04b5527b6)) -- **hooks:** export types ([#3159](https://github.com/algolia/react-instantsearch/issues/3159)) ([182348b](https://github.com/algolia/react-instantsearch/commit/182348b4a901823a7a41aee5d2b3bdc025cce48f)) -- **hooks:** expose `displayName` on Contexts ([#3168](https://github.com/algolia/react-instantsearch/issues/3168)) ([dafd3c6](https://github.com/algolia/react-instantsearch/commit/dafd3c66d05fbec09ebf907209ac25f55804e6f5)) -- **hooks:** friendly error when using Hooks with Core ([#3150](https://github.com/algolia/react-instantsearch/issues/3150)) ([d547ccf](https://github.com/algolia/react-instantsearch/commit/d547ccf7951299e2f6b1771e02fce052696ff65a)) -- **hooks:** introduce `useConnector()` ([#3137](https://github.com/algolia/react-instantsearch/issues/3137)) ([53e8afd](https://github.com/algolia/react-instantsearch/commit/53e8afd093b9950351467a16b82d528207ac34d2)) -- **hooks:** introduce `useHits()` ([#3147](https://github.com/algolia/react-instantsearch/issues/3147)) ([cc25cff](https://github.com/algolia/react-instantsearch/commit/cc25cff06e5ec216cba40fb8261372bc327001b6)) -- **hooks:** introduce `useRefinementList()` ([#3152](https://github.com/algolia/react-instantsearch/issues/3152)) ([0385cd9](https://github.com/algolia/react-instantsearch/commit/0385cd971635a8423ad687fab451d0778358389e)) -- **hooks:** introduce `useSearchBox()` ([#3146](https://github.com/algolia/react-instantsearch/issues/3146)) ([0d2c7f9](https://github.com/algolia/react-instantsearch/commit/0d2c7f9bd25b88cf725a1babd3b228ac804644c7)) -- **hooks:** trigger single network request on load ([#3167](https://github.com/algolia/react-instantsearch/issues/3167)) ([ff1ea49](https://github.com/algolia/react-instantsearch/commit/ff1ea49079a7800fd61ba99ceeb74b9f513eb99d)) -- **hooks:** type `useConnector()` return as render state ([#3169](https://github.com/algolia/react-instantsearch/issues/3169)) ([a801468](https://github.com/algolia/react-instantsearch/commit/a80146860164a092d2c90ee0aa4fcef88d5b675f)) -- **hooks:** update GitHub bug reports link ([#3157](https://github.com/algolia/react-instantsearch/issues/3157)) ([568b5c8](https://github.com/algolia/react-instantsearch/commit/568b5c83849a3927417907706656c3835163f216)) - - - -## [6.12.1](https://github.com/algolia/react-instantsearch/compare/v6.12.0...v6.12.1) (2021-08-02) - - -### Bug Fixes - -* **server side rendering:** return a value from mock currentRefinement/metadata ([#3078](https://github.com/algolia/react-instantsearch/issues/3078)) ([09f802b](https://github.com/algolia/react-instantsearch/commit/09f802b)) - - - -# [6.12.0](https://github.com/algolia/react-instantsearch/compare/v6.11.2...v6.12.0) (2021-07-06) - - -### Bug Fixes - -* **HitsPerPage:** Adds id prop to HitsPerPage, Select components ([#3072](https://github.com/algolia/react-instantsearch/issues/3072)) ([bc75d75](https://github.com/algolia/react-instantsearch/commit/bc75d75)) -* **MenuSelect:** Adds id prop to MenuSelect ([#3073](https://github.com/algolia/react-instantsearch/issues/3073)) ([fddaaef](https://github.com/algolia/react-instantsearch/commit/fddaaef)) -* **SearchBox:** Adds inputId prop to SearchBox ([#3074](https://github.com/algolia/react-instantsearch/issues/3074)) ([a05f6a4](https://github.com/algolia/react-instantsearch/commit/a05f6a4)) -* **SortBy:** Adds `id` prop to `SortBy`, `Select` components ([#3068](https://github.com/algolia/react-instantsearch/issues/3068)) ([1f2797f](https://github.com/algolia/react-instantsearch/commit/1f2797f)) - - -### Features - -* **DynamicWidgets:** add implementation ([#3056](https://github.com/algolia/react-instantsearch/issues/3056)) ([691ef87](https://github.com/algolia/react-instantsearch/commit/691ef87)) -* **facets:** add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu ([#3067](https://github.com/algolia/react-instantsearch/issues/3067)) ([731d9ba](https://github.com/algolia/react-instantsearch/commit/731d9ba)) - - - -## [6.11.2](https://github.com/algolia/react-instantsearch/compare/v6.11.1...v6.11.2) (2021-06-28) - - -### Bug Fixes - -* **maps:** leave zoom in place if the bounds did not change ([#3050](https://github.com/algolia/react-instantsearch/issues/3050)) ([c430598](https://github.com/algolia/react-instantsearch/commit/c430598)) - - - -## [6.11.1](https://github.com/algolia/react-instantsearch/compare/v6.11.0...v6.11.1) (2021-06-09) - - -### Bug Fixes - -* **RefinementList:** prevent searchable component to refine on empty list ([#3059](https://github.com/algolia/react-instantsearch/issues/3059)) ([04f3644](https://github.com/algolia/react-instantsearch/commit/04f3644)) - - - -# [6.11.0](https://github.com/algolia/react-instantsearch/compare/v6.10.3...v6.11.0) (2021-05-04) - - -### Features - -* **connectNumericMenu:** add support for floating point values ([#3047](https://github.com/algolia/react-instantsearch/issues/3047)) ([091bf57](https://github.com/algolia/react-instantsearch/commit/091bf57)) - - - -## [6.10.3](https://github.com/algolia/react-instantsearch/compare/v6.10.2...v6.10.3) (2021-03-03) - - -### Bug Fixes - -* **RelevantSort:** Rename `SmartSort` widget to `RelevantSort` ([#3026](https://github.com/algolia/react-instantsearch/issues/3026)) ([47d11bf](https://github.com/algolia/react-instantsearch/commit/47d11bf)) - - - -## [6.10.2](https://github.com/algolia/react-instantsearch/compare/v6.10.1...v6.10.2) (2021-03-03) - - -### Bug Fixes - -* **infiniteHits:** fix stale hits issue ([#3021](https://github.com/algolia/react-instantsearch/issues/3021)) ([a9a29c7](https://github.com/algolia/react-instantsearch/commit/a9a29c7)) - - - -## [6.10.1](https://github.com/algolia/react-instantsearch/compare/v6.10.0...v6.10.1) (2021-03-02) - - -### Bug Fixes - -* **SmartSort:** make `textComponent` and `buttonTextComponent` optional ([#3014](https://github.com/algolia/react-instantsearch/issues/3014)) ([682ee6d](https://github.com/algolia/react-instantsearch/commit/682ee6d)) - - - -# [6.10.0](https://github.com/algolia/react-instantsearch/compare/v6.9.0...v6.10.0) (2021-02-23) - - -### Bug Fixes - -* **infiniteHits:** do not cache the cached hits ([#3011](https://github.com/algolia/react-instantsearch/issues/3011)) ([b56f5f7](https://github.com/algolia/react-instantsearch/commit/b56f5f7)) - - -### Features - -* **smartSort:** add widget ([#3009](https://github.com/algolia/react-instantsearch/issues/3009)) ([4cc8412](https://github.com/algolia/react-instantsearch/commit/4cc8412)), closes [#3010](https://github.com/algolia/react-instantsearch/issues/3010) - - - -# [6.9.0](https://github.com/algolia/react-instantsearch/compare/v6.8.3...v6.9.0) (2021-02-03) - - -### Features - -* **answers:** add `EXPERIMENTAL_Answers` widget ([#2996](https://github.com/algolia/react-instantsearch/issues/2996)) ([55e4191](https://github.com/algolia/react-instantsearch/commit/55e4191)), closes [#3005](https://github.com/algolia/react-instantsearch/issues/3005) - - - -## [6.8.3](https://github.com/algolia/react-instantsearch/compare/v6.8.2...v6.8.3) (2021-01-22) - - -### Bug Fixes - -* upgrade prop-types dependency to 15.6+ ([#3003](https://github.com/algolia/react-instantsearch/issues/3003)) ([fc03496](https://github.com/algolia/react-instantsearch/commit/fc03496)) - - - -## [6.8.2](https://github.com/algolia/react-instantsearch/compare/v6.8.1...v6.8.2) (2020-10-21) - - -### Bug Fixes - -* **ssr:** provide metadata default value ([0a2f34c](https://github.com/algolia/react-instantsearch/commit/0a2f34c)) - - - -## [6.8.1](https://github.com/algolia/react-instantsearch/compare/v6.8.0...v6.8.1) (2020-10-14) - - -### Bug Fixes - -* **ssr:** hydrate metadata with a value ([9249c19](https://github.com/algolia/react-instantsearch/commit/9249c19)) - - - -# [6.8.0](https://github.com/algolia/react-instantsearch/compare/v6.7.0...v6.8.0) (2020-10-14) - - -### Bug Fixes - -* **ssr:** make sure metadata is available on initial render ([#2973](https://github.com/algolia/react-instantsearch/issues/2973)) ([be43b65](https://github.com/algolia/react-instantsearch/commit/be43b65)), closes [#2972](https://github.com/algolia/react-instantsearch/issues/2972) -* add missing dependencies ([#2975](https://github.com/algolia/react-instantsearch/issues/2975)) ([22ecb3c](https://github.com/algolia/react-instantsearch/commit/22ecb3c)) -* **ConfigureRelatedItems:** support nested attributes ([#2967](https://github.com/algolia/react-instantsearch/issues/2967)) ([86dfe86](https://github.com/algolia/react-instantsearch/commit/86dfe86)) -* **ssr:** allow "params" to be optional in custom clients ([#2961](https://github.com/algolia/react-instantsearch/issues/2961)) ([c3e3d2e](https://github.com/algolia/react-instantsearch/commit/c3e3d2e)), closes [#2958](https://github.com/algolia/react-instantsearch/issues/2958) - - - -# [6.7.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.7.0) (2020-07-20) - - -### Bug Fixes - -* **core:** appending successful index search results by returning new object reference ([#2953](https://github.com/algolia/react-instantsearch/issues/2953)) ([0a711a7](https://github.com/algolia/react-instantsearch/commit/0a711a7)) -* **ssr:** remove second instance of "query" in the response "params" for SSR ([#2945](https://github.com/algolia/react-instantsearch/issues/2945)) ([bf837c5](https://github.com/algolia/react-instantsearch/commit/bf837c5)), closes [#2941](https://github.com/algolia/react-instantsearch/issues/2941) - - -### Features - -* **infinite-hits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.6.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.6.0) (2020-06-15) - - -### Features - -* **infiniteHits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.5.0](https://github.com/algolia/react-instantsearch/compare/v6.4.0...v6.5.0) (2020-05-18) - - -### Bug Fixes - -* **connectQueryRules:** fix crash when using connectQueryRules with multiple indexes ([#2903](https://github.com/algolia/react-instantsearch/issues/2903)) ([c66d612](https://github.com/algolia/react-instantsearch/commit/c66d612)) -* **core:** fix maximum call stack size exceeded ([#2926](https://github.com/algolia/react-instantsearch/issues/2926)) ([7e883df](https://github.com/algolia/react-instantsearch/commit/7e883df)) - - -### Features - -* **SearchBox:** provide input element ref ([#2913](https://github.com/algolia/react-instantsearch/issues/2913)) ([b41bff2](https://github.com/algolia/react-instantsearch/commit/b41bff2)) - - - -# [6.4.0](https://github.com/algolia/react-instantsearch/compare/v6.3.0...v6.4.0) (2020-03-18) - - -### Bug Fixes - -* **deps:** fix "too much recursion" error with circular deps ([#2899](https://github.com/algolia/react-instantsearch/issues/2899)) ([c5f27a1](https://github.com/algolia/react-instantsearch/commit/c5f27a1)) - - - -# [6.3.0](https://github.com/algolia/react-instantsearch/compare/v6.2.0...v6.3.0) (2020-01-30) - - -### Features - -* **algoliasearch:** add support for algoliasearch v4 ([#2890](https://github.com/algolia/react-instantsearch/issues/2890)) ([c6c7382](https://github.com/algolia/react-instantsearch/commit/c6c7382)) - - - -# [6.2.0](https://github.com/algolia/react-instantsearch/compare/v6.1.0...v6.2.0) (2020-01-20) - - -### Bug Fixes - -* **deps:** update dependency algoliasearch to v3.35.1 ([#2802](https://github.com/algolia/react-instantsearch/issues/2802)) ([cfb91f0](https://github.com/algolia/react-instantsearch/commit/cfb91f0)) -* **widgets:** rename `ExperimentalConfigureRelatedItems` compon… ([#2891](https://github.com/algolia/react-instantsearch/issues/2891)) ([b910df2](https://github.com/algolia/react-instantsearch/commit/b910df2)) - - -### Features - -* **insights:** add getInsightsAnonymousUserToken helper ([#2887](https://github.com/algolia/react-instantsearch/issues/2887)) ([b5fe4f7](https://github.com/algolia/react-instantsearch/commit/b5fe4f7)) -* **widgets:** introduce `ConfigureRelatedItems` as experimental ([#2880](https://github.com/algolia/react-instantsearch/issues/2880)) ([923cd43](https://github.com/algolia/react-instantsearch/commit/923cd43)) - - - -# [6.1.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0...v6.1.0) (2019-12-17) - - -### Bug Fixes - -* **connectNumericMenu:** support numeric refinement 0 ([#2882](https://github.com/algolia/react-instantsearch/issues/2882)) ([30bd9fd](https://github.com/algolia/react-instantsearch/commit/30bd9fd)) -* **deps:** update dependency next to v9.1.1 ([9d49d33](https://github.com/algolia/react-instantsearch/commit/9d49d33)) -* **helper:** rely on stable version of algoliasearch-helper ([#2871](https://github.com/algolia/react-instantsearch/issues/2871)) ([e3531a1](https://github.com/algolia/react-instantsearch/commit/e3531a1)) - - -### Features - -* **insights:** show an error when 'clickAnalytics: true' is missing. ([#2877](https://github.com/algolia/react-instantsearch/issues/2877)) ([621656a](https://github.com/algolia/react-instantsearch/commit/621656a)) -* **voice:** add additionalQueryParameters ([#2366](https://github.com/algolia/react-instantsearch/issues/2366)) ([3a45b2c](https://github.com/algolia/react-instantsearch/commit/3a45b2c)) - - - -# [6.0.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.2...v6.0.0) (2019-10-28) - - - -# [6.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2019-10-25) - - -### Bug Fixes - -* serialize cache value on hydrate ([#2862](https://github.com/algolia/react-instantsearch/issues/2862)) ([3319665](https://github.com/algolia/react-instantsearch/commit/3319665)), closes [#2828](https://github.com/algolia/react-instantsearch/issues/2828) - - - -# [6.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.1) (2019-10-18) - - -### Bug Fixes - -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **deps:** update dependency antd to v3.19.3 ([#2530](https://github.com/algolia/react-instantsearch/issues/2530)) ([73636c5](https://github.com/algolia/react-instantsearch/commit/73636c5)) -* **deps:** update dependency antd to v3.19.4 ([#2559](https://github.com/algolia/react-instantsearch/issues/2559)) ([c3e8267](https://github.com/algolia/react-instantsearch/commit/c3e8267)) -* **deps:** update dependency antd to v3.19.5 ([#2560](https://github.com/algolia/react-instantsearch/issues/2560)) ([72efd31](https://github.com/algolia/react-instantsearch/commit/72efd31)) -* **deps:** update dependency antd to v3.19.6 ([#2564](https://github.com/algolia/react-instantsearch/issues/2564)) ([654f986](https://github.com/algolia/react-instantsearch/commit/654f986)) -* **deps:** update dependency antd to v3.19.7 ([#2573](https://github.com/algolia/react-instantsearch/issues/2573)) ([7e963ad](https://github.com/algolia/react-instantsearch/commit/7e963ad)) -* **deps:** update dependency antd to v3.19.8 ([#2584](https://github.com/algolia/react-instantsearch/issues/2584)) ([34dd9b2](https://github.com/algolia/react-instantsearch/commit/34dd9b2)) -* **deps:** update dependency antd to v3.20.0 ([#2611](https://github.com/algolia/react-instantsearch/issues/2611)) ([b976c67](https://github.com/algolia/react-instantsearch/commit/b976c67)) -* **deps:** update dependency antd to v3.20.1 ([#2635](https://github.com/algolia/react-instantsearch/issues/2635)) ([792ad9c](https://github.com/algolia/react-instantsearch/commit/792ad9c)) -* **deps:** update dependency antd to v3.20.2 ([#2655](https://github.com/algolia/react-instantsearch/issues/2655)) ([301c2d8](https://github.com/algolia/react-instantsearch/commit/301c2d8)) -* **deps:** update dependency antd to v3.20.3 ([#2658](https://github.com/algolia/react-instantsearch/issues/2658)) ([d078e70](https://github.com/algolia/react-instantsearch/commit/d078e70)) -* **deps:** update dependency antd to v3.20.5 ([#2686](https://github.com/algolia/react-instantsearch/issues/2686)) ([42ef821](https://github.com/algolia/react-instantsearch/commit/42ef821)) -* **deps:** update dependency antd to v3.20.6 ([#2711](https://github.com/algolia/react-instantsearch/issues/2711)) ([927fbfe](https://github.com/algolia/react-instantsearch/commit/927fbfe)) -* **deps:** update dependency antd to v3.20.7 ([#2712](https://github.com/algolia/react-instantsearch/issues/2712)) ([1830952](https://github.com/algolia/react-instantsearch/commit/1830952)) -* **deps:** update dependency antd to v3.21.1 ([#2736](https://github.com/algolia/react-instantsearch/issues/2736)) ([39a51a6](https://github.com/algolia/react-instantsearch/commit/39a51a6)) -* **deps:** update dependency antd to v3.21.2 ([#2738](https://github.com/algolia/react-instantsearch/issues/2738)) ([a7a998a](https://github.com/algolia/react-instantsearch/commit/a7a998a)) -* **deps:** update dependency antd to v3.21.4 ([#2747](https://github.com/algolia/react-instantsearch/issues/2747)) ([60012be](https://github.com/algolia/react-instantsearch/commit/60012be)) -* **deps:** update dependency antd to v3.22.0 ([#2758](https://github.com/algolia/react-instantsearch/issues/2758)) ([9cda468](https://github.com/algolia/react-instantsearch/commit/9cda468)) -* **deps:** update dependency antd to v3.22.2 ([#2791](https://github.com/algolia/react-instantsearch/issues/2791)) ([ff1f5d9](https://github.com/algolia/react-instantsearch/commit/ff1f5d9)) -* **deps:** update dependency antd to v3.23.2 ([#2814](https://github.com/algolia/react-instantsearch/issues/2814)) ([a190410](https://github.com/algolia/react-instantsearch/commit/a190410)) -* **deps:** update dependency lodash to v4.17.13 ([c4974cf](https://github.com/algolia/react-instantsearch/commit/c4974cf)) -* **deps:** update dependency lodash to v4.17.14 ([#2647](https://github.com/algolia/react-instantsearch/issues/2647)) ([a2d2dd5](https://github.com/algolia/react-instantsearch/commit/a2d2dd5)) -* **deps:** update dependency lodash to v4.17.15 ([#2684](https://github.com/algolia/react-instantsearch/issues/2684)) ([354143f](https://github.com/algolia/react-instantsearch/commit/354143f)) -* **deps:** update dependency next to v9 ([#2638](https://github.com/algolia/react-instantsearch/issues/2638)) ([d22f61d](https://github.com/algolia/react-instantsearch/commit/d22f61d)) -* **deps:** update dependency next to v9.0.1 ([#2652](https://github.com/algolia/react-instantsearch/issues/2652)) ([2c2dab9](https://github.com/algolia/react-instantsearch/commit/2c2dab9)) -* **deps:** update dependency next to v9.0.2 ([#2662](https://github.com/algolia/react-instantsearch/issues/2662)) ([6fa4c5e](https://github.com/algolia/react-instantsearch/commit/6fa4c5e)) -* **deps:** update dependency next to v9.0.3 ([#2724](https://github.com/algolia/react-instantsearch/issues/2724)) ([f51b04b](https://github.com/algolia/react-instantsearch/commit/f51b04b)) -* **deps:** update dependency next to v9.0.4 ([#2767](https://github.com/algolia/react-instantsearch/issues/2767)) ([9af9180](https://github.com/algolia/react-instantsearch/commit/9af9180)) -* **deps:** update dependency next to v9.0.5 ([#2789](https://github.com/algolia/react-instantsearch/issues/2789)) ([0a75f41](https://github.com/algolia/react-instantsearch/commit/0a75f41)) -* **deps:** update dependency qs to v6.8.0 ([#2757](https://github.com/algolia/react-instantsearch/issues/2757)) ([8bffb87](https://github.com/algolia/react-instantsearch/commit/8bffb87)) -* **deps:** update dependency react-compound-slider to v2.1.0 ([#2610](https://github.com/algolia/react-instantsearch/issues/2610)) ([3389ee5](https://github.com/algolia/react-instantsearch/commit/3389ee5)) -* **deps:** update dependency react-compound-slider to v2.2.0 ([#2649](https://github.com/algolia/react-instantsearch/issues/2649)) ([7b81af1](https://github.com/algolia/react-instantsearch/commit/7b81af1)) -* **deps:** update dependency react-native-vector-icons to v6.5.0 ([#2520](https://github.com/algolia/react-instantsearch/issues/2520)) ([5f7f5b6](https://github.com/algolia/react-instantsearch/commit/5f7f5b6)) -* **deps:** update dependency react-native-vector-icons to v6.6.0 ([#2599](https://github.com/algolia/react-instantsearch/issues/2599)) ([b6bb199](https://github.com/algolia/react-instantsearch/commit/b6bb199)) -* **deps:** update dependency react-router-dom to v5.0.1 ([#2506](https://github.com/algolia/react-instantsearch/issues/2506)) ([d762230](https://github.com/algolia/react-instantsearch/commit/d762230)) -* **highlight:** switch to index as key ([#2691](https://github.com/algolia/react-instantsearch/issues/2691)) ([17e75d1](https://github.com/algolia/react-instantsearch/commit/17e75d1)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### chore - -* **release:** 6.0.0-beta.1 ([#2861](https://github.com/algolia/react-instantsearch/issues/2861)) ([cb56ca0](https://github.com/algolia/react-instantsearch/commit/cb56ca0)), closes [#2023](https://github.com/algolia/react-instantsearch/issues/2023) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2203](https://github.com/algolia/react-instantsearch/issues/2203) [#2432](https://github.com/algolia/react-instantsearch/issues/2432) [#2444](https://github.com/algolia/react-instantsearch/issues/2444) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2454](https://github.com/algolia/react-instantsearch/issues/2454) [#2455](https://github.com/algolia/react-instantsearch/issues/2455) [#2459](https://github.com/algolia/react-instantsearch/issues/2459) [#2458](https://github.com/algolia/react-instantsearch/issues/2458) [#2460](https://github.com/algolia/react-instantsearch/issues/2460) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2446](https://github.com/algolia/react-instantsearch/issues/2446) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2466](https://github.com/algolia/react-instantsearch/issues/2466) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2555](https://github.com/algolia/react-instantsearch/issues/2555) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2349](https://github.com/algolia/react-instantsearch/issues/2349) [#2570](https://github.com/algolia/react-instantsearch/issues/2570) [#2462](https://github.com/algolia/react-instantsearch/issues/2462) [#2600](https://github.com/algolia/react-instantsearch/issues/2600) [#2468](https://github.com/algolia/react-instantsearch/issues/2468) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2621](https://github.com/algolia/react-instantsearch/issues/2621) [#2627](https://github.com/algolia/react-instantsearch/issues/2627) [#2644](https://github.com/algolia/react-instantsearch/issues/2644) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2645](https://github.com/algolia/react-instantsearch/issues/2645) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2643](https://github.com/algolia/react-instantsearch/issues/2643) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2722](https://github.com/algolia/react-instantsearch/issues/2722) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2701](https://github.com/algolia/react-instantsearch/issues/2701) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2530](https://github.com/algolia/react-instantsearch/issues/2530) [#2559](https://github.com/algolia/react-instantsearch/issues/2559) [#2560](https://github.com/algolia/react-instantsearch/issues/2560) [#2564](https://github.com/algolia/react-instantsearch/issues/2564) [#2573](https://github.com/algolia/react-instantsearch/issues/2573) [#2584](https://github.com/algolia/react-instantsearch/issues/2584) [#2611](https://github.com/algolia/react-instantsearch/issues/2611) [#2635](https://github.com/algolia/react-instantsearch/issues/2635) [#2655](https://github.com/algolia/react-instantsearch/issues/2655) [#2658](https://github.com/algolia/react-instantsearch/issues/2658) [#2686](https://github.com/algolia/react-instantsearch/issues/2686) [#2711](https://github.com/algolia/react-instantsearch/issues/2711) [#2712](https://github.com/algolia/react-instantsearch/issues/2712) [#2736](https://github.com/algolia/react-instantsearch/issues/2736) [#2738](https://github.com/algolia/react-instantsearch/issues/2738) [#2747](https://github.com/algolia/react-instantsearch/issues/2747) [#2758](https://github.com/algolia/react-instantsearch/issues/2758) [#2647](https://github.com/algolia/react-instantsearch/issues/2647) [#2684](https://github.com/algolia/react-instantsearch/issues/2684) [#2638](https://github.com/algolia/react-instantsearch/issues/2638) [#2652](https://github.com/algolia/react-instantsearch/issues/2652) [#2662](https://github.com/algolia/react-instantsearch/issues/2662) [#2724](https://github.com/algolia/react-instantsearch/issues/2724) [#2767](https://github.com/algolia/react-instantsearch/issues/2767) [#2757](https://github.com/algolia/react-instantsearch/issues/2757) [#2610](https://github.com/algolia/react-instantsearch/issues/2610) [#2649](https://github.com/algolia/react-instantsearch/issues/2649) [#2520](https://github.com/algolia/react-instantsearch/issues/2520) [#2599](https://github.com/algolia/react-instantsearch/issues/2599) [#2506](https://github.com/algolia/react-instantsearch/issues/2506) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2688](https://github.com/algolia/react-instantsearch/issues/2688) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2535](https://github.com/algolia/react-instantsearch/issues/2535) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2834](https://github.com/algolia/react-instantsearch/issues/2834) [#2845](https://github.com/algolia/react-instantsearch/issues/2845) [#2842](https://github.com/algolia/react-instantsearch/issues/2842) [#2852](https://github.com/algolia/react-instantsearch/issues/2852) [#2853](https://github.com/algolia/react-instantsearch/issues/2853) - - -### BREAKING CHANGES - -* **release:** translation will render default value if passed undefined as value - -* chore(lodash): remove imports - -* fix(translation): allow undefined value to be passed on purpose -* **release:** no longer do we allow paths like `attribute[5].something`, or other indexed forms, only `.` is allowed as special key. - -All existing tests still pass, and we never documented you could use `lodash.get` patterns other than `.`. - -* feat(get): accept array & bracked-separated string - -moved to utils at the same time - -* fix typo - -* feedback: test for undefined behaviour - -* chore(size): update expectation - -this will go down afterwards, but for now there's some more duplication - - - -# [6.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.0) (2019-08-21) - -[Migration guide](MIGRATION.md) - -### Bug Fixes - -* **react 17 compat:** upgrade RangeInput lifecycle ([#2289](https://github.com/algolia/react-instantsearch/issues/2289)) ([110b1af](https://github.com/algolia/react-instantsearch/commit/110b1af)) -* **react 17 compat:** upgrade RangeSlider lifecycle ([#2290](https://github.com/algolia/react-instantsearch/issues/2290)) ([69a7f53](https://github.com/algolia/react-instantsearch/commit/69a7f53)) -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **core:** searchState can be non-Object object ([#2722](https://github.com/algolia/react-instantsearch/issues/2722)) ([dea493c](https://github.com/algolia/react-instantsearch/commit/dea493c)), closes [#2568](https://github.com/algolia/react-instantsearch/issues/2568) -* **createConnector:** new React life cycles ([#2357](https://github.com/algolia/react-instantsearch/issues/2357)) ([fc10640](https://github.com/algolia/react-instantsearch/commit/fc10640)) -* **createInstantSearchManager:** do not trigger search on index update ([#2552](https://github.com/algolia/react-instantsearch/issues/2552)) ([e209362](https://github.com/algolia/react-instantsearch/commit/e209362)) -* **geo:** check for undefined in isEqual ([#2643](https://github.com/algolia/react-instantsearch/issues/2643)) ([a544231](https://github.com/algolia/react-instantsearch/commit/a544231)), closes [#2467](https://github.com/algolia/react-instantsearch/issues/2467) -* **geo:** remove lifecycle compat ([#2644](https://github.com/algolia/react-instantsearch/issues/2644)) ([2b2b898](https://github.com/algolia/react-instantsearch/commit/2b2b898)), closes [#2626](https://github.com/algolia/react-instantsearch/issues/2626) -* **highlight:** switch to index as key ([#2690](https://github.com/algolia/react-instantsearch/issues/2690)) ([51de682](https://github.com/algolia/react-instantsearch/commit/51de682)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **peerDependencies:** update React ([#2626](https://github.com/algolia/react-instantsearch/issues/2626)) ([6ccad49](https://github.com/algolia/react-instantsearch/commit/6ccad49)) -* **ssr:** avoid duplicate serializing ([#2726](https://github.com/algolia/react-instantsearch/issues/2726)) ([c768b1a](https://github.com/algolia/react-instantsearch/commit/c768b1a)) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### Code Refactoring - -* **lodash:** get ([#2461](https://github.com/algolia/react-instantsearch/issues/2461)) ([527b879](https://github.com/algolia/react-instantsearch/commit/527b879)) -* **lodash:** has ([#2434](https://github.com/algolia/react-instantsearch/issues/2434)) ([75a4a15](https://github.com/algolia/react-instantsearch/commit/75a4a15)) -* **lodash:** has been fully removed - -### Features - -* **autocomplete:** add queryID & position to provided hits ([#2687](https://github.com/algolia/react-instantsearch/issues/2687)) ([e453dab](https://github.com/algolia/react-instantsearch/commit/e453dab)) -* **client:** remove algoliaClient, appId & apiKey ([#2338](https://github.com/algolia/react-instantsearch/issues/2338)) ([b84a0b5](https://github.com/algolia/react-instantsearch/commit/b84a0b5)) (use searchClient exclusively now) -* **context:** migrate to new React context ([#2178](https://github.com/algolia/react-instantsearch/issues/2178)) ([0a1abea](https://github.com/algolia/react-instantsearch/commit/0a1abea)), closes [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) -* **ssr:** update the SSR API ([#2555](https://github.com/algolia/react-instantsearch/issues/2555)) ([925bdb8](https://github.com/algolia/react-instantsearch/commit/925bdb8)), closes [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) - - -### BREAKING CHANGES - -* **searchClient:** argument is the only option now. - -Previously there were three options to pass a search client: searchClient, appId & apiKey, algoliaClient. The latter two have been removed, and now only `searchClient` is accepted. This searchClient is an instance of the `algoliasearch` module: - -```js -import algoliasearch from 'algoliasearch/lite'; - -const searchClient = algoliasearch( - 'myAppId', - 'myApiKey', - { _useRequestCache: true } -); - -// ... - -``` - -If you were relying on duplicate requests not being fired when using appId & apiKey before, you need to enable the `_useRequestCache` option now. - -* **SSR:** imports have changed - -In the server, you now directly import `findResultsState`, which now requires a `searchClient` in the second argument. - -In the App, you now use a regular `InstantSearch` component. - -* **Index & InstantSearch:** Remove `root` DOM element - -These elements now are pure containers for their children, and don't add a `div` to the DOM anymore. If you were relying on those for styling, wrap the `InstantSearch` and `Index` element with a `div` with an appropriate class. - -* **Index & InstantSearch:** Remove support for `root` prop - -Since these two arguments now no longer wrap their children in an element, they no longer accept a `root` prop. - -* **Highlight:** some paths will no longer be accepted - -We only accept paths separated with a dot or bracket now, like before. It's possible that a different type of path worked undocumented, but no longer does. - -* **algoliasearch-helper:** updating to the next major version - -This library is mostly internal, but it has had a major refactor (including removing lodash). This has no impact, unless you are dealing with it using `createConnector`. See the [migration guide](https://github.com/algolia/algoliasearch-helper-js/blob/next/documentation-src/metalsmith/content/upgrade.md) for the v3 of algoliasearch-helper for more information. - -# [5.7.0](https://github.com/algolia/react-instantsearch/compare/v5.6.0...v5.7.0) (2019-06-04) - - -### Bug Fixes - -* **highlight:** allow array as "attribute" ([#2474](https://github.com/algolia/react-instantsearch/issues/2474)) ([9dc829a](https://github.com/algolia/react-instantsearch/commit/9dc829a)), closes [#2461](https://github.com/algolia/react-instantsearch/issues/2461) -* **indexUtils:** allow index with dots in it ([#2350](https://github.com/algolia/react-instantsearch/issues/2350)) ([f91906f](https://github.com/algolia/react-instantsearch/commit/f91906f)) - - -### Features - -* **voiceSearch:** add voice search widget ([#2316](https://github.com/algolia/react-instantsearch/issues/2316)) ([0e3b124](https://github.com/algolia/react-instantsearch/commit/0e3b124)) - - - -# [5.6.0](https://github.com/algolia/react-instantsearch/compare/v5.5.0...v5.6.0) (2019-05-15) - - -### Bug Fixes - -* **connectQueryRules:** avoid to throw an error with undefined values ([#2436](https://github.com/algolia/react-instantsearch/issues/2436)) ([1e18287](https://github.com/algolia/react-instantsearch/commit/1e18287)) - - -### Features - -* **infiniteHits:** add previous button ([#2296](https://github.com/algolia/react-instantsearch/issues/2296)) ([010a69a](https://github.com/algolia/react-instantsearch/commit/010a69a)) - - - -# [5.5.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0...v5.5.0) (2019-04-23) - - -### Bug Fixes - -* **createInstantSearch:** change the User-Agent to use the new specs ([#2209](https://github.com/algolia/react-instantsearch/issues/2209)) ([642ba0b](https://github.com/algolia/react-instantsearch/commit/642ba0b)) - - -### Features - -* **DOMMaps:** expose withGoogleMaps HOC [PART-1] ([#2000](https://github.com/algolia/react-instantsearch/issues/2000)) ([2ae1dea](https://github.com/algolia/react-instantsearch/commit/2ae1dea)) -* **queryRules:** add Query Rules features ([#2286](https://github.com/algolia/react-instantsearch/issues/2286)) ([3ae9c01](https://github.com/algolia/react-instantsearch/commit/3ae9c01)) -* **insights:** add insights features ([#2215](https://github.com/algolia/react-instantsearch/pull/2215)) ([961e7a7](https://github.com/algolia/react-instantsearch/commit/961e7a7)) - - - -# [5.4.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.1...v5.4.0) (2019-02-05) - - -### Bug Fixes - -* **DOMMaps:** set React & React DOM as peer deps ([#1922](https://github.com/algolia/react-instantsearch/issues/1922)) ([2f2cefd](https://github.com/algolia/react-instantsearch/commit/2f2cefd)) - - - -# [5.4.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.0...v5.4.0-beta.1) (2019-01-10) - - -### Bug Fixes - -* **deps:** sync algoliasearch version ([#1879](https://github.com/algolia/react-instantsearch/issues/1879)) ([40f9c26](https://github.com/algolia/react-instantsearch/commit/40f9c26)) -* **maps:** use stable version for peer deps ([#1887](https://github.com/algolia/react-instantsearch/issues/1887)) ([9055167](https://github.com/algolia/react-instantsearch/commit/9055167)) - - - -# [5.4.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.3.2...v5.4.0-beta.0) (2019-01-08) - - -### Features - -* **Index:** introduce `indexId` prop ([#1833](https://github.com/algolia/react-instantsearch/issues/1833)) ([ec9e0fb](https://github.com/algolia/react-instantsearch/commit/ec9e0fb)) - - - - -## [5.3.2](https://github.com/algolia/react-instantsearch/compare/v5.3.1...v5.3.2) (2018-10-30) - - -### Bug Fixes - -* **sffv:** clamp maxFacetHits to the allowed range ([#1696](https://github.com/algolia/react-instantsearch/issues/1696)) ([83ce245](https://github.com/algolia/react-instantsearch/commit/83ce245)) - - - - -## [5.3.1](https://github.com/algolia/react-instantsearch/compare/v5.3.0...v5.3.1) (2018-09-26) - - -### Bug Fixes - -* **connector:** ensure canRefine is computed on the transformed items ([#1568](https://github.com/algolia/react-instantsearch/pull/1568)) ([c95384f](https://github.com/algolia/react-instantsearch/commit/c95384f)) -* **toggle:** ensure facet is present ([#1613](https://github.com/algolia/react-instantsearch/issues/1613)) ([e914ff6](https://github.com/algolia/react-instantsearch/commit/e914ff6)) - - - - -# [5.3.0](https://github.com/algolia/react-instantsearch/compare/v5.2.3...v5.3.0) (2018-09-24) - - -### Bug Fixes - -* **SSR:** bind getSearchParmaters to the component instance ([f34cb3d](https://github.com/algolia/react-instantsearch/commit/f34cb3d)) -* **GoogleMapsLoader:** pick google maps version ([#1540](https://github.com/algolia/react-instantsearch/issues/1540)) ([b14efcf](https://github.com/algolia/react-instantsearch/commit/b14efcf)) - - -### Features - -* **connectToggleRefinement:** implement canRefine & count ([#1588](https://github.com/algolia/react-instantsearch/issues/1588)) ([40672dd](https://github.com/algolia/react-instantsearch/commit/40672dd)) - - - - -## [5.2.3](https://github.com/algolia/react-instantsearch/compare/v5.2.2...v5.2.3) (2018-08-16) - - -### Bug Fixes - -* Allow object as type for Root (closes [#1446](https://github.com/algolia/react-instantsearch/issues/1446)) ([#1461](https://github.com/algolia/react-instantsearch/issues/1461)) ([7c2317b](https://github.com/algolia/react-instantsearch/commit/7c2317b)) -* **List:** render children list only when required ([#1472](https://github.com/algolia/react-instantsearch/issues/1472)) ([9eb2cbb](https://github.com/algolia/react-instantsearch/commit/9eb2cbb)), closes [#1459](https://github.com/algolia/react-instantsearch/issues/1459) - - - - -## [5.2.2](https://github.com/algolia/react-instantsearch/compare/v5.2.1...v5.2.2) (2018-07-16) - - -Publish the previous version on `stable`. - - - - -## [5.2.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0...v5.2.1) (2018-07-16) - - -### Bug Fixes - -* **GoogleMapsLoader:** inline the import to scriptjs ([#1427](https://github.com/algolia/react-instantsearch/issues/1427)) ([8019416](https://github.com/algolia/react-instantsearch/commit/8019416)) - - - - -# [5.2.0](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.2...v5.2.0) (2018-07-04) - - -### Bug Fixes - -* **translatable:** avoid create a new function on every render ([#1383](https://github.com/algolia/react-instantsearch/issues/1383)) ([1285b3b](https://github.com/algolia/react-instantsearch/commit/1285b3b)) - - -### Features - -* **core:** export translatable ([#1351](https://github.com/algolia/react-instantsearch/issues/1351)) ([6d5a89d](https://github.com/algolia/react-instantsearch/commit/6d5a89d)) -* **maps:** add connector & widget ([#1171](https://github.com/algolia/react-instantsearch/issues/1171)) ([16e288a](https://github.com/algolia/react-instantsearch/commit/16e288a)) - - - - -# [5.2.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.1...v5.2.0-beta.2) (2018-06-19) - - -### Features - -* export highlight tags from DOM / native ([#1342](https://github.com/algolia/react-instantsearch/issues/1342)) ([28a699e](https://github.com/algolia/react-instantsearch/commit/28a699e)) -* **createInstantSearch:** enable _useRequestCache ([#1346](https://github.com/algolia/react-instantsearch/issues/1346)) ([f772600](https://github.com/algolia/react-instantsearch/commit/f772600)) -* **dom:** export create class name ([#1348](https://github.com/algolia/react-instantsearch/issues/1348)) ([9017468](https://github.com/algolia/react-instantsearch/commit/9017468)) - - - - -# [5.2.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.0...v5.2.0-beta.1) (2018-06-04) - - -### Bug Fixes - -* **dom:** publish server file ([#1305](https://github.com/algolia/react-instantsearch/issues/1305)) ([bd79693](https://github.com/algolia/react-instantsearch/commit/bd79693)) - - - - -# [5.2.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.1.0...v5.2.0-beta.0) (2018-06-04) - - -This new version introduce a complete revamp of the package structure, but it should be completely transparent for the users. - -If you have any troubles with this version please open a issue on [Github](https://github.com/algolia/react-instantsearch/issues/new), thanks! - - - - -# [5.1.0](https://github.com/algolia/react-instantsearch/compare/v5.0.3...v5.1.0) (2018-05-28) - - -### Bug Fixes - -* **connectInfiniteHits:** always set a value for previous page ([#1195](https://github.com/algolia/react-instantsearch/issues/1195)) ([4c218d5](https://github.com/algolia/react-instantsearch/commit/4c218d5)) -* **indexUtils:** avoid throw an error on cleanUp multi indices ([#1265](https://github.com/algolia/react-instantsearch/issues/1265)) ([12f5ace](https://github.com/algolia/react-instantsearch/commit/12f5ace)) - - -### Features - -* **searchClient:** Add support for custom Search Clients ([#1216](https://github.com/algolia/react-instantsearch/issues/1216)) ([174cc28](https://github.com/algolia/react-instantsearch/commit/174cc28)) - - - - -## [5.0.3](https://github.com/algolia/react-instantsearch/compare/v5.0.2...v5.0.3) (2018-04-03) - - -### Bug Fixes - -* revert dependencies as devDependencies ([#1135](https://github.com/algolia/react-instantsearch/issues/1135)) ([6b627bb](https://github.com/algolia/react-instantsearch/commit/6b627bb)) - - - - -## [5.0.2](https://github.com/algolia/react-instantsearch/compare/v5.0.1...v5.0.2) (2018-04-03) - - -### Bug Fixes - -* use lodash version of unsupported Array.{fill, find} ([#1118](https://github.com/algolia/react-instantsearch/issues/1118)) ([ea7bf42](https://github.com/algolia/react-instantsearch/commit/ea7bf42)) - - - - -## [5.0.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0...v5.0.1) (2018-03-12) - - -### Bug Fixes - -* **connectInfiniteHits:** always provide an array for hits ([#1064](https://github.com/algolia/react-instantsearch/issues/1064)) ([c75e38b](https://github.com/algolia/react-instantsearch/commit/c75e38b)) - - - - -# [5.0.0](https://github.com/algolia/react-instantsearch/compare/v4.5.2...v5.0.0) (2018-03-06) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.5.2](https://github.com/algolia/react-instantsearch/compare/v4.5.1...v4.5.2) (2018-03-06) - - -### Bug Fixes - -* **connectRange:** update default refinement propTypes ([#978](https://github.com/algolia/react-instantsearch/issues/978)) ([c065fb1](https://github.com/algolia/react-instantsearch/commit/c065fb1)) -* **IndexUtils:** avoid throw an error when cleanUp multi index ([#1019](https://github.com/algolia/react-instantsearch/issues/1019)) ([865a3c3](https://github.com/algolia/react-instantsearch/commit/865a3c3)) -* **SearchBox:** avoid to bind click on reset button ([#979](https://github.com/algolia/react-instantsearch/issues/979)) ([ea3063a](https://github.com/algolia/react-instantsearch/commit/ea3063a)) - - - - -# [5.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2018-02-06) - - -Apply features & bug fixes from [v4.5.0](#450-2018-02-06) & [v4.5.1](#451-2018-02-06) on the v5. - -See their CHANGELOG for more details. - - - - -## [4.5.1](https://github.com/algolia/react-instantsearch/compare/v4.5.0...v4.5.1) (2018-02-06) - - -### Bug Fixes - -* **StarRating:** move to 1 based instead of 0 ([#949](https://github.com/algolia/react-instantsearch/issues/949)) ([eb0152d](https://github.com/algolia/react-instantsearch/commit/eb0152d)) - - - - -# [4.5.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v4.5.0) (2018-02-06) - - -### Bug Fixes - -* **connectRange:** use the same behaviour for currentRefinement in getMetadata ([#923](https://github.com/algolia/react-instantsearch/issues/923)) ([08917b6](https://github.com/algolia/react-instantsearch/commit/08917b6)) -* **connectToggle:** use currentRefinement in metadata instead of the label ([#909](https://github.com/algolia/react-instantsearch/issues/909)) ([89cae2b](https://github.com/algolia/react-instantsearch/commit/89cae2b)) -* **StarRatings:** always show the stars below ([#929](https://github.com/algolia/react-instantsearch/issues/929)) ([22bf93a](https://github.com/algolia/react-instantsearch/commit/22bf93a)) - - -### Features - -* **connectStateResults:** expose isSearchStalled ([#933](https://github.com/algolia/react-instantsearch/issues/933)) ([f45ba27](https://github.com/algolia/react-instantsearch/commit/f45ba27)) - - - -# [5.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v5.0.0-beta.0) (2018-01-30) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.4.2](https://github.com/algolia/react-instantsearch/compare/v4.4.1...v4.4.2) (2018-01-24) - - -### Bug Fixes - -* **currentRefinements:** give access to id and index from transformItems for deduplication ([#830](https://github.com/algolia/react-instantsearch/issues/830)) ([316b8f5](https://github.com/algolia/react-instantsearch/commit/316b8f5)) -* pass maxFacetHits to SFFV ([#863](https://github.com/algolia/react-instantsearch/issues/863)) ([de23a46](https://github.com/algolia/react-instantsearch/commit/de23a46)) - - - - -## [4.4.1](https://github.com/algolia/react-instantsearch/compare/v4.4.0...v4.4.1) (2018-01-09) - - -### Bug Fixes - -* **SearchBox**: clear SearchBox without search as you type ([#802](https://github.com/algolia/react-instantsearch/issues/802)) ([c49b2b6](https://github.com/algolia/react-instantsearch/commit/c49b2b6)) -* **connectRange:** check if facet exist before access ([#797](https://github.com/algolia/react-instantsearch/issues/797)) ([6520760](https://github.com/algolia/react-instantsearch/commit/6520760)) -* **stories:** avoid to use linear-background it breaks Argos every time ([#804](https://github.com/algolia/react-instantsearch/issues/804)) ([0beded7](https://github.com/algolia/react-instantsearch/commit/0beded7)) -* **stories:** limit hits per page on Index ([#806](https://github.com/algolia/react-instantsearch/issues/806)) ([6eb14d3](https://github.com/algolia/react-instantsearch/commit/6eb14d3)) - - -### Features - -* **Index:** allow custom root ([#792](https://github.com/algolia/react-instantsearch/issues/792)) ([d793b0a](https://github.com/algolia/react-instantsearch/commit/d793b0a)) - - - - -# [4.4.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0...v4.4.0) (2018-01-03) - - -### Bug Fixes - -* **createInstantSearch:** remove the client from the Snapshot ([#749](https://github.com/algolia/react-instantsearch/issues/749)) ([700d8f4](https://github.com/algolia/react-instantsearch/commit/700d8f4)) -* refresh cache memory leak example ([#784](https://github.com/algolia/react-instantsearch/issues/784)) ([cf228ac](https://github.com/algolia/react-instantsearch/commit/cf228ac)) -* **stories:** rename InstantSearch to `` ([#789](https://github.com/algolia/react-instantsearch/issues/789)) ([05efda5](https://github.com/algolia/react-instantsearch/commit/05efda5)) - - -### Features - -* InstantSearch root props ([#770](https://github.com/algolia/react-instantsearch/issues/770)) ([2d458f8](https://github.com/algolia/react-instantsearch/commit/2d458f8)) - - - - -# [4.3.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0-beta.0...v4.3.0) (2017-12-20) - - -### Bug Fixes - -* reset page with multi index ([#665](https://github.com/algolia/react-instantsearch/issues/665)) ([865b7dc](https://github.com/algolia/react-instantsearch/commit/865b7dc)) -* track all index in the manager ([#660](https://github.com/algolia/react-instantsearch/issues/660)) ([793502b](https://github.com/algolia/react-instantsearch/commit/793502b)) - - -### Features - -* **SearchBox:** provide a loading indicator ([#544](https://github.com/algolia/react-instantsearch/issues/544)) ([189659e](https://github.com/algolia/react-instantsearch/commit/189659e)) -* **Highlight:** support array of strings ([#715](https://github.com/algolia/react-instantsearch/issues/715)) ([8e93c6a](https://github.com/algolia/react-instantsearch/commit/8e93c6a)) - - - - -# [4.3.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.2.0...v4.3.0-beta.0) (2017-11-27) - - -### Bug Fixes - -* **babelrc:** add a key for each env development, production, es ([#547](https://github.com/algolia/react-instantsearch/issues/547)) ([fa9528d](https://github.com/algolia/react-instantsearch/commit/fa9528d)) -* **localizecount:** allow localized string for count in MenuSelect ([#657](https://github.com/algolia/react-instantsearch/issues/657)) ([67ebd34](https://github.com/algolia/react-instantsearch/commit/67ebd34)) -* **react-router-example:** Properly update search query when using browser navigation ([#604](https://github.com/algolia/react-instantsearch/issues/604)) ([9ee6600](https://github.com/algolia/react-instantsearch/commit/9ee6600)) - - -### Features - -* **refreshcache:** add prop refresh to InstantSearch instance ([#619](https://github.com/algolia/react-instantsearch/issues/619)) ([19f6de0](https://github.com/algolia/react-instantsearch/commit/19f6de0)) - - - - -# [4.2.0](https://github.com/algolia/react-instantsearch/compare/v4.1.3...v4.2.0) (2017-11-02) - - -### Bug Fixes - -* **connectRange:** handle boundaries on first call ([9f14dc0](https://github.com/algolia/react-instantsearch/commit/9f14dc0)) -* **connectRange:** use refine instead of cleanUp in metadata ([#526](https://github.com/algolia/react-instantsearch/issues/526)) ([1861235](https://github.com/algolia/react-instantsearch/commit/1861235)) -* **hierarchicaMenu:** allow sorting and using limit ([fe178ed](https://github.com/algolia/react-instantsearch/commit/fe178ed)), closes [#92](https://github.com/algolia/react-instantsearch/issues/92) -* **InfiniteHits:** add disabled style to the LoadMore button ([#477](https://github.com/algolia/react-instantsearch/issues/477)) ([faba1ad](https://github.com/algolia/react-instantsearch/commit/faba1ad)) -* **Range:** handle float, allow reset and respect boundaries ([75969b8](https://github.com/algolia/react-instantsearch/commit/75969b8)) -* **RangeInput:** fix compatibility with React 16 & Panel ([3f218db](https://github.com/algolia/react-instantsearch/commit/3f218db)) -* **searchbox:** add maxlength 512 ([#542](https://github.com/algolia/react-instantsearch/issues/542)) ([5bd4033](https://github.com/algolia/react-instantsearch/commit/5bd4033)), closes [#510](https://github.com/algolia/react-instantsearch/issues/510) - - -### Features - -* **MenuSelect:** add component and connector ([cc6e0d7](https://github.com/algolia/react-instantsearch/commit/cc6e0d7)) - - - - -## [4.1.3](https://github.com/algolia/react-instantsearch/compare/v4.1.2...v4.1.3) (2017-10-09) - - -### Bug Fixes - -* **List:** remove React16 warning ([#442](https://github.com/algolia/react-instantsearch/issues/442)) ([8d6cf18](https://github.com/algolia/react-instantsearch/commit/8d6cf18)) - - -### Features - -* **connectStateResults:** add component props ([#434](https://github.com/algolia/react-instantsearch/issues/434)) ([c629b97](https://github.com/algolia/react-instantsearch/commit/c629b97)) - - - - -## [4.1.2](https://github.com/algolia/react-instantsearch/compare/v4.1.1...v4.1.2) (2017-09-26) - - -### Features - -* **Conditional:** add connectStateResults connector ([#357](https://github.com/algolia/react-instantsearch/issues/357)) ([462df5f](https://github.com/algolia/react-instantsearch/commit/462df5f)) - - - - -## [4.1.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0...v4.1.1) (2017-09-13) - - -### Bug Fixes - -* **MultiIndex:** reset page to 1 when share widgets refine (#312) ([c85a7bf](https://github.com/algolia/react-instantsearch/commit/c85a7bf)) -* **MultiIndex:** Trigger new search when `` props are updated (#318) ([bb11965](https://github.com/algolia/react-instantsearch/commit/bb11965)) - - - - -# [4.1.0](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.5...v4.1.0) (2017-08-28) - - -### Bug Fixes - -* **Highlighting:** revert breaking change (#245) ([045ee06](https://github.com/algolia/react-instantsearch/commit/045ee06)) -* **List:** adds support for any type of renderable element (#266) ([d848bb6](https://github.com/algolia/react-instantsearch/commit/d848bb6)) -* **Pagination:** fixed the offset ([3c0fff2](https://github.com/algolia/react-instantsearch/commit/3c0fff2)) -* **PoweredBy:** aria-* tags are not camelcased (#261) ([dc4a5bb](https://github.com/algolia/react-instantsearch/commit/dc4a5bb)) - - - - -# [4.1.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2017-08-08) - - -### Bug Fixes - -* **SSR:** clean SP before rendering agan (#238) ([e765886](https://github.com/algolia/react-instantsearch/commit/e765886)) - - -### Features - -* **Breadcrumb:** add a new widget & connector (#228) ([7f8f3ae](https://github.com/algolia/react-instantsearch/commit/7f8f3ae)) - - - - -# [4.1.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2017-08-03) - - -### Bug Fixes - -* **deps:** Update dependency lint-staged to version ^4.0.0 (#201) ([6867a1b](https://github.com/algolia/react-instantsearch/commit/6867a1b)) -* **nextjs/ssr:** parse `params.asPath` (#189) ([ae17da0](https://github.com/algolia/react-instantsearch/commit/ae17da0)) -* **PoweredBy:** add a label to the Algolia logo (#216) ([cd235bd](https://github.com/algolia/react-instantsearch/commit/cd235bd)) -* **react:** remove typo around `"" 2` (#220) ([f73eb04](https://github.com/algolia/react-instantsearch/commit/f73eb04)) -* **ScrollTo:** scroll to only if change triggered by the widget observed (#202) ([2d76022](https://github.com/algolia/react-instantsearch/commit/2d76022)) -* **theme:** format the count of items appearing in a refinement (#217) ([2225c24](https://github.com/algolia/react-instantsearch/commit/2225c24)) - - - - -# [4.1.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2017-07-25) - - -### Bug Fixes - -* **error:** reset error when receiving results of a query (not when sending it) (#179) ([bb12c29](https://github.com/algolia/react-instantsearch/commit/bb12c29)) -* **highlight:** wrong parsing between client and server (#183) ([2daae70](https://github.com/algolia/react-instantsearch/commit/2daae70)) -* **poweredBy:** SSR compatibility (#181) ([ec0fa8a](https://github.com/algolia/react-instantsearch/commit/ec0fa8a)) - - -### BREAKING CHANGES - -* **highlight:** We remove the timestamp present in our highlight preTag and postTag. If you were using regex to parse the -highlighting results then you'll need to adapt it as now it's only "ais-highlight". - - - - -# [4.1.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2017-07-20) - - -### Bug Fixes - -* **error:** reset error if next query is successful (#175) ([ff50a07](https://github.com/algolia/react-instantsearch/commit/ff50a07)) - - - - -# [4.1.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2017-07-12) - - - - -# [4.1.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.0.7...v4.1.0-beta.0) (2017-07-10) - - -### Bug Fixes - -* **argos:** address flakyness (#152) ([84ef8f1](https://github.com/algolia/react-instantsearch/commit/84ef8f1)) - - -### Features - -* **server-side rendering:** Add API features for server-side rendering ([86b14d1](https://github.com/algolia/react-instantsearch/commit/86b14d1)) - - - - -## [4.0.7](https://github.com/algolia/react-instantsearch/compare/v4.0.6...v4.0.7) (2017-07-06) - - -### Bug Fixes - -* **results:** revert commit that ensure hits are returned only if right indices (#149) ([df9aa25](https://github.com/algolia/react-instantsearch/commit/df9aa25)) - - - - -## [4.0.6](https://github.com/algolia/react-instantsearch/compare/v4.0.5...v4.0.6) (2017-06-29) - - -### Bug Fixes - -* **store:** delay call to listener to prevent infinite loops (#143) ([0945958](https://github.com/algolia/react-instantsearch/commit/0945958)) - - - - -## [4.0.5](https://github.com/algolia/react-instantsearch/compare/v4.0.4...v4.0.5) (2017-06-26) - - -### Bug Fixes - -* **MultiIndex:** ensure getResults return only hits matching index in the context (#136) ([124ffe6](https://github.com/algolia/react-instantsearch/commit/124ffe6)) -* **MultiIndex:** handle if namespace isn't in search state (#139) ([1aab324](https://github.com/algolia/react-instantsearch/commit/1aab324)) -* **storybook:** process CSS through autoprefixer (#138) ([62cf512](https://github.com/algolia/react-instantsearch/commit/62cf512)) - - - - -## [4.0.4](https://github.com/algolia/react-instantsearch/compare/v4.0.3...v4.0.4) (2017-06-19) - - -### Bug Fixes - -* **MultiIndex:** handle switch between mono and multi index (#132) ([e161921](https://github.com/algolia/react-instantsearch/commit/e161921)) - - - - -## [4.0.3](https://github.com/algolia/react-instantsearch/compare/v4.0.2...v4.0.3) (2017-06-14) - - -### Bug Fixes - -* **SFFV:** search status we're not inside search state (#125) ([5f3e670](https://github.com/algolia/react-instantsearch/commit/5f3e670)) - - - - -## [4.0.2](https://github.com/algolia/react-instantsearch/compare/v4.0.1...v4.0.2) (2017-05-30) - - - - -## [4.0.1](https://github.com/algolia/react-instantsearch/compare/v4.0.0...v4.0.1) (2017-05-17) - - -### Bug Fixes - -* **state:** nested attributes for faceting were not handled ([11bd122](https://github.com/algolia/react-instantsearch/commit/11bd122)) - - - - -# [4.0.0](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.6...v4.0.0) (2017-05-15) - -### Features and migration guide - -You can find all the details of the release and the migration guide from v3 to v4 here: https://discourse.algolia.com/t/react-instantsearch-v4/1329. - - - -# [4.0.0-beta.6](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2017-05-04) - - - - -# [4.0.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2017-05-02) - - -### Bug Fixes - -* **connectAutoComplete:** allow usage with hits from a single index (#75) ([8b3b358](https://github.com/algolia/react-instantsearch/commit/8b3b358)), closes [#74](https://github.com/algolia/react-instantsearch/issues/74) -* **InstantSearch:** update algoliaClient when it change (#70) ([9e97dbd](https://github.com/algolia/react-instantsearch/commit/9e97dbd)) - - - - -# [4.0.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2017-04-25) - - -### Bug Fixes - -* **MultIndex:** no need to nest hits, if those are from main index. (#56) ([86e0bd7](https://github.com/algolia/react-instantsearch/commit/86e0bd7)) - - -### Features - -* **MultiIndex:** remove the need for virtual hits when using connectAutoComplete (#45) ([7549019](https://github.com/algolia/react-instantsearch/commit/7549019)) - - - - -# [4.0.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2017-04-21) - - -### Bug Fixes - -* replace usage of Object.values (#47) ([4c79e3e](https://github.com/algolia/react-instantsearch/commit/4c79e3e)) - - - - -# [4.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2017-04-18) - - -### Bug Fixes - -* **InstantSearch:** dont fire request/onsearchStateChange when unmounting (#26) ([9a1487a](https://github.com/algolia/react-instantsearch/commit/9a1487a)) -* **MultiIndex:** derived helper were using main index specifics params (#36) ([991fea6](https://github.com/algolia/react-instantsearch/commit/991fea6)) -* **MultiIndex:** revert breaking change if no multiple index (#32) ([44f7de0](https://github.com/algolia/react-instantsearch/commit/44f7de0)) -* **util:** remove empty key was removing non object key (#29) ([9f795c7](https://github.com/algolia/react-instantsearch/commit/9f795c7)) - - -### Features - -* **Highlighter:** allow rendering to custom tag (#11) ([52a1212](https://github.com/algolia/react-instantsearch/commit/52a1212)) -* **SearchBox:** add default width and height to buttons. (#34) ([bcabf9b](https://github.com/algolia/react-instantsearch/commit/bcabf9b)) - - - - -# [4.0.0-beta.1](https://github.com/algolia/instantsearch.js/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2017-04-03) - - -### Bug Fixes - -* **SFFV:** fix wrong query behaviour with slow network (#2086) ([c251e8f](https://github.com/algolia/instantsearch.js/commit/c251e8f)), closes [#2086](https://github.com/algolia/instantsearch.js/issues/2086) - - - - -# [4.0.0-beta.0](https://github.com/algolia/instantsearch.js/compare/v3.3.0...v4.0.0-beta.0) (2017-03-28) - - -### Features - -* **multi-index:** ease multi index and auto complete ([09a4e1d](https://github.com/algolia/instantsearch.js/commit/09a4e1d)) - - -### BREAKING CHANGES - -* multi-index: * Reseting the pagination should be done at each connector level inside the "refine" function when returning the search state. -* The current page now appears inside the search state when a widget is used -* Query values are part of the items prop of the connectCurrentRefinements connector. Behaviour is unchanged, query will be filtered if clearsQuery prop is false. -* Add the index name to all the current refinements items. (not used by our widgets yet, but available if needed). - - - - -# [3.3.0](https://github.com/algolia/instantsearch.js/compare/v3.2.2-beta0...v3.3.0) (2017-03-22) - - -### Bug Fixes - -* **example:** Fix access to props in react-router example ([1417d6f](https://github.com/algolia/instantsearch.js/commit/1417d6f)) - - - - -## [3.2.2-beta0](https://github.com/algolia/instantsearch.js/compare/v3.2.1...v3.2.2-beta0) (2017-03-20) - - -### Bug Fixes - -* **InfiniteHits:** provide translation key for `Load More` (#2048) ([6130bf2](https://github.com/algolia/instantsearch.js/commit/6130bf2)) -* **SearchBox:** better mobile behaviour by default ([ea968b3](https://github.com/algolia/instantsearch.js/commit/ea968b3)) -* **example:** link to instantsearch/react (#2007) ([5e674cd](https://github.com/algolia/instantsearch.js/commit/5e674cd)) -* **recipes:** react router v4 ([de673bf](https://github.com/algolia/instantsearch.js/commit/de673bf)) - - -### Features - -* **SearchBox:** add role=search to the form (#2046) ([d1e90f3](https://github.com/algolia/instantsearch.js/commit/d1e90f3)) -* **SearchBox:** allow custom reset and submit components (#1991) ([cd303d7](https://github.com/algolia/instantsearch.js/commit/cd303d7)) -* **searchBox:** add event handling ([e267ab6](https://github.com/algolia/instantsearch.js/commit/e267ab6)), closes [#2017](https://github.com/algolia/instantsearch.js/issues/2017) - - - - -## [3.2.1](https://github.com/algolia/instantsearch.js/compare/v3.2.0...v3.2.1) (2017-02-22) - - -### Bug Fixes - -* **umd:** Add connectors to UMD build (#1988) ([23ac5e6](https://github.com/algolia/instantsearch.js/commit/23ac5e6)), closes [#1987](https://github.com/algolia/instantsearch.js/issues/1987) - - - - -# [3.2.0](https://github.com/algolia/instantsearch.js/compare/v3.1.0...v3.2.0) (2017-02-15) - - -### Bug Fixes - -* **Configure:** use props a unique source of truth (#1967) ([9d53d86](https://github.com/algolia/instantsearch.js/commit/9d53d86)) -* **SearchBox:** Safari can only have with xlinkHref (#1970) ([7ab00bd](https://github.com/algolia/instantsearch.js/commit/7ab00bd)), closes [#1968](https://github.com/algolia/instantsearch.js/issues/1968) - - -### Features - -* **MultiRange:** add an all range (#1959) ([a3dc950](https://github.com/algolia/instantsearch.js/commit/a3dc950)) - - -### BREAKING CHANGES - -* MultiRange: - MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system. - - - - -# [3.1.0](https://github.com/algolia/instantsearch.js/compare/v3.0.0...v3.1.0) (2017-02-08) - - -### Bug Fixes - -* **Configure:** call onSearchStateChange when props are updated (#1953) ([7e151db](https://github.com/algolia/instantsearch.js/commit/7e151db)), closes [#1950](https://github.com/algolia/instantsearch.js/issues/1950) -* **Configure:** trigger onSearchStateChange with the right data ([11e5af8](https://github.com/algolia/instantsearch.js/commit/11e5af8)) -* **createConnector:** updates with latest props on state change (#1951) ([cd3a82c](https://github.com/algolia/instantsearch.js/commit/cd3a82c)) - - -### Features - -* **ClearAll:** add withQuery to also clear the search query (#1958) ([c0e695b](https://github.com/algolia/instantsearch.js/commit/c0e695b)) - - - - -# [3.0.0](https://github.com/algolia/instantsearch.js/compare/v2.2.5...v3.0.0) (2017-02-06) - - -### Bug Fixes - -* ***List:** disable shortcuts in *List SearchBoxes (#1921) ([51a76ae](https://github.com/algolia/instantsearch.js/commit/51a76ae)), closes [#1920](https://github.com/algolia/instantsearch.js/issues/1920) -* **Configure:** add configure parameters in search state (#1935) ([0971330](https://github.com/algolia/instantsearch.js/commit/0971330)), closes [#1863](https://github.com/algolia/instantsearch.js/issues/1863) -* **Hits:** limit the hitComponent to be only a function (#1912) ([b3c9578](https://github.com/algolia/instantsearch.js/commit/b3c9578)) -* **Pagination:** fix and indicate when pagination is disabled ([5f20199](https://github.com/algolia/instantsearch.js/commit/5f20199)), closes [#1938](https://github.com/algolia/instantsearch.js/issues/1938) -* **StarRating:** usage with filters (#1933) ([667e9d5](https://github.com/algolia/instantsearch.js/commit/667e9d5)) -* **withSearchBox:** keep displaying searchBox when no items found (#1930) ([30de4cd](https://github.com/algolia/instantsearch.js/commit/30de4cd)) - - -### Features - -* **MultiRange:** indicate if a range has no refinements (#1926) ([80b6450](https://github.com/algolia/instantsearch.js/commit/80b6450)) -* **panel:** add a panel widget (#1889) ([594e1a1](https://github.com/algolia/instantsearch.js/commit/594e1a1)) -* **starRating:** indicate when any refinement has no effect ([c547ae5](https://github.com/algolia/instantsearch.js/commit/c547ae5)) -* **widgets:** default design for disabled states (#1929) ([31f010b](https://github.com/algolia/instantsearch.js/commit/31f010b)) - -### Migration guide - -The migration to V3.0.0 should be safe and you should do it. - -There are two breaking changes that you will need to handle in your codebase: -- Anytime you are using a connector, when there are no more items in it or no more hits, we will still call your Component. Thus you will have to handle cases like dealing with empty arrays and decide if you want to unmount or hide the widget. -- Anytime you are using a widget, when there are no more items in it or no more hits, we will still display the widget. You can then decide to hide it with CSS. - - -## [2.2.5](https://github.com/algolia/instantsearch.js/compare/v2.2.4...v2.2.5) (2017-01-23) - - -### Bug Fixes - -* **currentRefinements:** make removing a toggle refinement work ([8995e64](https://github.com/algolia/instantsearch.js/commit/8995e64)) - - - - -## [2.2.4](https://github.com/algolia/instantsearch.js/compare/v2.2.3...v2.2.4) (2017-01-20) - - -### Bug Fixes - -* **publish:** publish react-instantsearch/dist instead of root (#1884) ([64414e0](https://github.com/algolia/instantsearch.js/commit/64414e0)) - - - - -## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-01-20) - - -### Bug Fixes - -* **SFFV:** translations for searchbox were not applied (#1879) ([e9b4ee1](https://github.com/algolia/instantsearch.js/commit/e9b4ee1)) - - - - -## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-01-18) - - -### Bug Fixes - -* **react-router:** search was triggered two many times (#1840) ([25e9db5](https://github.com/algolia/instantsearch.js/commit/25e9db5)) -* **SFFV:** empty query triggered a new SFFV (#1875) ([6c8259a](https://github.com/algolia/instantsearch.js/commit/6c8259a)) - - - - -## [2.2.1](https://github.com/algolia/instantsearch.js/compare/v2.2.0...v2.2.1) (2017-01-18) - - -### Bug Fixes - -* **createInstantsearch:** fix missing props (#1867) ([8d319b5](https://github.com/algolia/instantsearch.js/commit/8d319b5)), closes [#1867](https://github.com/algolia/instantsearch.js/issues/1867) - - - - -# [2.2.0](https://github.com/algolia/instantsearch.js/compare/v2.1.0...v2.2.0) (2017-01-17) - - -### Bug Fixes - -* **clear:** clearing wasn't working with too+ same type facets selected (#1820) ([a9a2364](https://github.com/algolia/instantsearch.js/commit/a9a2364)) -* **connectSearchBox:** handle `defaultRefinement` (#1829) ([7a730e2](https://github.com/algolia/instantsearch.js/commit/7a730e2)), closes [#1826](https://github.com/algolia/instantsearch.js/issues/1826) -* **Instantsearch:** Update all props on InstantSearch (#1828) ([2ed9b49](https://github.com/algolia/instantsearch.js/commit/2ed9b49)) -* **InstantSearch:** add specific `react-instantsearch ${version}` agent (#1844) ([a1113bc](https://github.com/algolia/instantsearch.js/commit/a1113bc)) -* **SFFV:** correct propTypes and add missing default values (#1845) ([a4c1b31](https://github.com/algolia/instantsearch.js/commit/a4c1b31)) -* **test:** add missing Snippet and Highliter snapshot ([4accce5](https://github.com/algolia/instantsearch.js/commit/4accce5)) -* **widgets:** replace setImmediate use with Promise use when update is needed (#1811) ([17e2497](https://github.com/algolia/instantsearch.js/commit/17e2497)) - - -### Features - -* **Menu, connectMenu:** add search for facet values (#1822) ([a6c513e](https://github.com/algolia/instantsearch.js/commit/a6c513e)) -* **snippet:** add a snippet widget to be able to highlight snippet results (#1797) ([2aecc40](https://github.com/algolia/instantsearch.js/commit/2aecc40)) -* **widgets:** add transformItems to be able to sort and filter (#1809) ([ba539f0](https://github.com/algolia/instantsearch.js/commit/ba539f0)) - - - - -# [2.1.0](https://github.com/algolia/instantsearch.js/compare/v2.0.1...v2.1.0) (2017-01-04) - - -### Bug Fixes - -* **createInstantSearchManager:** drop outdated response (#1765) ([76c5312](https://github.com/algolia/instantsearch.js/commit/76c5312)) -* **highlight:** highlight should work even if the attribute is missing (#1791) ([5b79b15](https://github.com/algolia/instantsearch.js/commit/5b79b15)), closes [#1790](https://github.com/algolia/instantsearch.js/issues/1790) -* **InfiniteHits:** better classname to loadmore btn (#1789) ([ad2ded3](https://github.com/algolia/instantsearch.js/commit/ad2ded3)) -* **starRatings:** click on selected range doesn't unselect it (#1766) ([beacc72](https://github.com/algolia/instantsearch.js/commit/beacc72)) -* **website:** broken demo links (#1802) ([0abe2f5](https://github.com/algolia/instantsearch.js/commit/0abe2f5)) -* **widgets:** add 300px width for the default SearchBox (#1803) ([bf5d791](https://github.com/algolia/instantsearch.js/commit/bf5d791)) - - -### Features - -* **InfiniteHits:** Add class to load more button (#1787) ([416febd](https://github.com/algolia/instantsearch.js/commit/416febd)) -* **RefinementList, connectRefinementList:** allow to search for facet values ([e086a81](https://github.com/algolia/instantsearch.js/commit/e086a81)) - - - - -## [2.0.1](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.1) (2016-12-15) - - -### Bug Fixes - -* **connectRange:** when unfinite numbers are passed throw ([75bec0d](https://github.com/algolia/instantsearch.js/commit/75bec0d)) -* **react-native:** use View as a container for react-native (#1729) ([5b76f75](https://github.com/algolia/instantsearch.js/commit/5b76f75)), closes [#1730](https://github.com/algolia/instantsearch.js/issues/1730) -* **SearchBox:** autocomplete was not disabled by default (#1742) ([bc76618](https://github.com/algolia/instantsearch.js/commit/bc76618)) -* **starRating:** call createURL with the right interface (min/max) (#1747) ([f9ab9b6](https://github.com/algolia/instantsearch.js/commit/f9ab9b6)) - - - - -## [2.0.0](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.0) (2016-12-08) - -First release of `react-instantsearch` diff --git a/packages/react-instantsearch-dom/README.md b/packages/react-instantsearch-dom/README.md deleted file mode 100644 index 19a1b7845d..0000000000 --- a/packages/react-instantsearch-dom/README.md +++ /dev/null @@ -1,13 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [react-instantsearch-dom](#react-instantsearch-dom) - - - -# react-instantsearch-dom - -This is the [React](https://facebook.github.io/react) version of Algolia's `instantsearch` library. - -Go to the [React InstantSearch website](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/) or the [React InstantSearch GitHub repository](https://github.com/algolia/instantsearch.js) for more information. diff --git a/packages/react-instantsearch-dom/package.json b/packages/react-instantsearch-dom/package.json deleted file mode 100644 index 9e04e9304c..0000000000 --- a/packages/react-instantsearch-dom/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "react-instantsearch-dom", - "version": "6.40.4", - "description": "⚡ Lightning-fast search for React DOM, by Algolia", - "main": "dist/cjs/index.js", - "module": "dist/es/index.js", - "sideEffects": false, - "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/", - "repository": { - "type": "git", - "url": "https://github.com/algolia/instantsearch.js" - }, - "author": { - "name": "Algolia, Inc.", - "url": "https://www.algolia.com" - }, - "keywords": [ - "algolia", - "components", - "fast", - "instantsearch", - "react", - "react-dom", - "search" - ], - "files": [ - "README.md", - "server.js", - "dist" - ], - "scripts": { - "clean": "rm -rf dist", - "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es && yarn build:umd", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:umd": "BABEL_ENV=rollup rollup -c rollup.config.js", - "storybook": "start-storybook -p 6006 -c .storybook -s .storybook/public", - "storybook:build": "build-storybook -c .storybook -s .storybook/public -o ../../website/stories/react" - }, - "dependencies": { - "@babel/runtime": "^7.1.2", - "algoliasearch-helper": "3.14.0", - "classnames": "^2.2.5", - "prop-types": "^15.6.2", - "react-fast-compare": "^3.0.0", - "react-instantsearch-core": "6.40.4" - }, - "devDependencies": { - "@storybook/react": "5.3.9", - "babel-preset-react-app": "10.0.1", - "lodash.orderby": "4.6.0", - "nock": "11.7.2", - "react-autosuggest": "9.4.3" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.3.0 < 19", - "react-dom": ">= 16.3.0 < 19" - } -} diff --git a/packages/react-instantsearch-dom/rollup.config.js b/packages/react-instantsearch-dom/rollup.config.js deleted file mode 100644 index 5ceedb8a32..0000000000 --- a/packages/react-instantsearch-dom/rollup.config.js +++ /dev/null @@ -1,75 +0,0 @@ -import babel from 'rollup-plugin-babel'; -import commonjs from 'rollup-plugin-commonjs'; -import filesize from 'rollup-plugin-filesize'; -import globals from 'rollup-plugin-node-globals'; -import resolve from 'rollup-plugin-node-resolve'; -import replace from 'rollup-plugin-replace'; -import { uglify } from 'rollup-plugin-uglify'; - -const clear = (x) => x.filter(Boolean); - -const version = process.env.VERSION || 'UNRELEASED'; -const algolia = '© Algolia, inc.'; -const link = 'https://github.com/algolia/instantsearch.js'; -const createBanner = (name) => - `/*! React InstantSearch${name} ${version} | ${algolia} | ${link} */`; - -const plugins = [ - babel({ - exclude: /node_modules|algoliasearch-helper/, - extensions: ['.js', '.ts', '.tsx'], - rootMode: 'upward', - runtimeHelpers: true, - }), - resolve({ - browser: true, - preferBuiltins: false, - extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], - }), - commonjs(), - globals(), - replace({ - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - filesize({ - showMinifiedSize: false, - showGzippedSize: true, - }), -]; - -const createConfiguration = ({ name, minify = false } = {}) => ({ - input: 'src/index.js', - external: ['react', 'react-dom'], - output: { - file: `dist/umd/ReactInstantSearch${name}${minify ? '.min' : ''}.js`, - name: `ReactInstantSearch${name}`, - format: 'umd', - globals: { - react: 'React', - 'react-dom': 'ReactDOM', - }, - banner: createBanner(name), - sourcemap: true, - }, - plugins: plugins.concat( - clear([ - minify && - uglify({ - output: { - preamble: createBanner(name), - }, - }), - ]) - ), -}); - -export default [ - createConfiguration({ - name: 'DOM', - }), - - createConfiguration({ - name: 'DOM', - minify: true, - }), -]; diff --git a/packages/react-instantsearch-dom/server.js b/packages/react-instantsearch-dom/server.js deleted file mode 100644 index 4b85d99189..0000000000 --- a/packages/react-instantsearch-dom/server.js +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable import/no-commonjs, no-var */ - -// This file only exist to allow the import from 'react-instantsearch-dom/server' -// We can't have this import working easily with the current project architecture. -// The main reason is that we require to have the files transpiled at development -// time to allow the import accross Workspaces (node_modules are not transpiled). -// To achieve this we scope all the packages artefacts in the `dist` folder under -// `/cjs` & `/es`. At the end we can require the package as it is with a `main` -// that point to `./dist/cjs/index.js` & `module` that point to the `es` folder. -// But the `/server` import will fallback into this file instead of the correct -// one the `dist` folder. -// We now have the solution for those use cases: private packages. You can have -// nested private packages inside your "main" package. The advantage of this -// approach is to leverage the module resolution of npm. A popular package built -// with this approach is Preact 10.x.x: https://bit.ly/2WrMjLF - -var server = require('./dist/cjs/server'); - -module.exports = server; diff --git a/packages/react-instantsearch-dom/src/components/Breadcrumb.js b/packages/react-instantsearch-dom/src/components/Breadcrumb.js deleted file mode 100644 index b511e8b85d..0000000000 --- a/packages/react-instantsearch-dom/src/components/Breadcrumb.js +++ /dev/null @@ -1,95 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -import Link from './Link'; - -const cx = createClassNames('Breadcrumb'); - -const itemsPropType = PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, - }) -); - -class Breadcrumb extends Component { - static propTypes = { - canRefine: PropTypes.bool.isRequired, - createURL: PropTypes.func.isRequired, - items: itemsPropType, - refine: PropTypes.func.isRequired, - rootURL: PropTypes.string, - separator: PropTypes.node, - translate: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - rootURL: null, - separator: ' > ', - className: '', - }; - - render() { - const { - canRefine, - createURL, - items, - refine, - rootURL, - separator, - translate, - className, - } = this.props; - const rootPath = canRefine ? ( -
  • - (!rootURL ? refine() : null)} - href={rootURL ? rootURL : createURL()} - > - {translate('rootLabel')} - -
  • - ) : null; - - const breadcrumb = items.map((item, idx) => { - const isLast = idx === items.length - 1; - return ( -
  • - {separator} - {!isLast ? ( - refine(item.value)} - href={createURL(item.value)} - > - {item.label} - - ) : ( - item.label - )} -
  • - ); - }); - - return ( -
    -
      - {rootPath} - {breadcrumb} -
    -
    - ); - } -} - -export default translatable({ - rootLabel: 'Home', -})(Breadcrumb); diff --git a/packages/react-instantsearch-dom/src/components/ClearRefinements.js b/packages/react-instantsearch-dom/src/components/ClearRefinements.js deleted file mode 100644 index 604b3d99f7..0000000000 --- a/packages/react-instantsearch-dom/src/components/ClearRefinements.js +++ /dev/null @@ -1,42 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('ClearRefinements'); - -class ClearRefinements extends Component { - static propTypes = { - items: PropTypes.arrayOf(PropTypes.object).isRequired, - canRefine: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - translate: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - render() { - const { items, canRefine, refine, translate, className } = this.props; - - return ( -
    - -
    - ); - } -} - -export default translatable({ - reset: 'Clear all filters', -})(ClearRefinements); diff --git a/packages/react-instantsearch-dom/src/components/CurrentRefinements.js b/packages/react-instantsearch-dom/src/components/CurrentRefinements.js deleted file mode 100644 index 528ffad008..0000000000 --- a/packages/react-instantsearch-dom/src/components/CurrentRefinements.js +++ /dev/null @@ -1,72 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('CurrentRefinements'); - -export const CurrentRefinements = ({ - items, - canRefine, - refine, - translate, - className, -}) => ( -
    -
      - {items.map((item) => ( -
    • - {item.label} - {item.items ? ( - item.items.map((nest) => ( - - {nest.label} - - - )) - ) : ( - - - - )} -
    • - ))} -
    -
    -); - -const itemPropTypes = PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string.isRequired, - value: PropTypes.func.isRequired, - items: (...args) => itemPropTypes(...args), - }) -); - -CurrentRefinements.propTypes = { - items: itemPropTypes.isRequired, - canRefine: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - translate: PropTypes.func.isRequired, - className: PropTypes.string, -}; - -CurrentRefinements.defaultProps = { - className: '', -}; - -export default translatable({ - clearFilter: '✕', -})(CurrentRefinements); diff --git a/packages/react-instantsearch-dom/src/components/HierarchicalMenu.js b/packages/react-instantsearch-dom/src/components/HierarchicalMenu.js deleted file mode 100644 index 8e9c94642a..0000000000 --- a/packages/react-instantsearch-dom/src/components/HierarchicalMenu.js +++ /dev/null @@ -1,82 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -import Link from './Link'; -import List from './List'; - -const cx = createClassNames('HierarchicalMenu'); - -const itemsPropType = PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string.isRequired, - value: PropTypes.string, - count: PropTypes.number.isRequired, - items: (...args) => itemsPropType(...args), - }) -); - -class HierarchicalMenu extends Component { - static propTypes = { - translate: PropTypes.func.isRequired, - refine: PropTypes.func.isRequired, - createURL: PropTypes.func.isRequired, - canRefine: PropTypes.bool.isRequired, - items: itemsPropType, - showMore: PropTypes.bool, - className: PropTypes.string, - limit: PropTypes.number, - showMoreLimit: PropTypes.number, - transformItems: PropTypes.func, - }; - - static defaultProps = { - className: '', - }; - - renderItem = (item) => { - const { createURL, refine } = this.props; - - return ( - refine(item.value)} - href={createURL(item.value)} - > - {item.label}{' '} - {item.count} - - ); - }; - - render() { - const { - translate, - items, - showMore, - limit, - showMoreLimit, - canRefine, - className, - } = this.props; - return ( - - ); - } -} - -export default translatable({ - showMore: (extended) => (extended ? 'Show less' : 'Show more'), -})(HierarchicalMenu); diff --git a/packages/react-instantsearch-dom/src/components/Highlight.js b/packages/react-instantsearch-dom/src/components/Highlight.js deleted file mode 100644 index 72446675da..0000000000 --- a/packages/react-instantsearch-dom/src/components/Highlight.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -import { createClassNames } from '../core/utils'; - -import Highlighter from './Highlighter'; - -const cx = createClassNames('Highlight'); - -const Highlight = (props) => ( - -); - -export default Highlight; diff --git a/packages/react-instantsearch-dom/src/components/Highlighter.js b/packages/react-instantsearch-dom/src/components/Highlighter.js deleted file mode 100644 index 4441fe6e3d..0000000000 --- a/packages/react-instantsearch-dom/src/components/Highlighter.js +++ /dev/null @@ -1,101 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; - -export const Highlight = ({ - cx, - value, - highlightedTagName, - isHighlighted, - nonHighlightedTagName, -}) => { - const TagName = isHighlighted ? highlightedTagName : nonHighlightedTagName; - const className = isHighlighted ? 'highlighted' : 'nonHighlighted'; - return {value}; -}; - -Highlight.propTypes = { - cx: PropTypes.func.isRequired, - value: PropTypes.string.isRequired, - isHighlighted: PropTypes.bool.isRequired, - highlightedTagName: PropTypes.string.isRequired, - nonHighlightedTagName: PropTypes.string.isRequired, -}; - -const Highlighter = ({ - cx, - hit, - attribute, - highlight, - highlightProperty, - tagName, - nonHighlightedTagName, - separator, - className, -}) => { - const parsedHighlightedValue = highlight({ - hit, - attribute, - highlightProperty, - }); - - return ( - - {parsedHighlightedValue.map((item, i) => { - if (Array.isArray(item)) { - const isLast = i === parsedHighlightedValue.length - 1; - return ( - - {item.map((element, index) => ( - - ))} - {!isLast && {separator}} - - ); - } - - return ( - - ); - })} - - ); -}; - -Highlighter.propTypes = { - cx: PropTypes.func.isRequired, - hit: PropTypes.object.isRequired, - attribute: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.string), - PropTypes.string, - ]).isRequired, - highlight: PropTypes.func.isRequired, - highlightProperty: PropTypes.string.isRequired, - tagName: PropTypes.string, - nonHighlightedTagName: PropTypes.string, - className: PropTypes.string, - separator: PropTypes.node, -}; - -Highlighter.defaultProps = { - tagName: 'em', - nonHighlightedTagName: 'span', - className: '', - separator: ', ', -}; - -export default Highlighter; diff --git a/packages/react-instantsearch-dom/src/components/Hits.tsx b/packages/react-instantsearch-dom/src/components/Hits.tsx deleted file mode 100644 index 5f5798538c..0000000000 --- a/packages/react-instantsearch-dom/src/components/Hits.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import { createClassNames } from '../core/utils'; - -type Hit = { - objectID: string | number; -}; - -type HitProps = { - hit: Hit; -}; - -type Props = { - hits: Hit[]; - className?: string; - hitComponent?: - | string - | React.ElementType - | React.ExoticComponent; -}; - -const cx = createClassNames('Hits'); - -const DefaultHitComponent: React.FC = (props) => ( -
    - {JSON.stringify(props).slice(0, 100)} - ... -
    -); - -const Hits: React.FC = ({ - hits, - className = '', - hitComponent: HitComponent = DefaultHitComponent, -}) => ( -
    -
      - {hits.map((hit) => ( -
    • - -
    • - ))} -
    -
    -); - -const HitPropTypes = PropTypes.shape({ - objectID: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, -}); - -Hits.propTypes = { - hits: PropTypes.arrayOf(HitPropTypes.isRequired).isRequired, - className: PropTypes.string, - - // this is actually PropTypes.elementType, but our prop-types version is outdated - hitComponent: PropTypes.any, -}; - -export default Hits; diff --git a/packages/react-instantsearch-dom/src/components/HitsPerPage.js b/packages/react-instantsearch-dom/src/components/HitsPerPage.js deleted file mode 100644 index 0fc1e95f56..0000000000 --- a/packages/react-instantsearch-dom/src/components/HitsPerPage.js +++ /dev/null @@ -1,46 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import { createClassNames } from '../core/utils'; - -import Select from './Select'; - -const cx = createClassNames('HitsPerPage'); - -class HitsPerPage extends Component { - static propTypes = { - id: PropTypes.string, - items: PropTypes.arrayOf( - PropTypes.shape({ - value: PropTypes.number.isRequired, - label: PropTypes.string, - }) - ).isRequired, - currentRefinement: PropTypes.number.isRequired, - refine: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - render() { - const { id, items, currentRefinement, refine, className } = this.props; - - return ( -
    - - - - {items.map((item) => ( - - ))} - -
    - ); - } -} - -export default translatable({ - seeAllOption: 'See all', -})(MenuSelect); diff --git a/packages/react-instantsearch-dom/src/components/NumericMenu.js b/packages/react-instantsearch-dom/src/components/NumericMenu.js deleted file mode 100644 index d6a39a052a..0000000000 --- a/packages/react-instantsearch-dom/src/components/NumericMenu.js +++ /dev/null @@ -1,68 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -import List from './List'; - -const cx = createClassNames('NumericMenu'); - -class NumericMenu extends Component { - static propTypes = { - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.node.isRequired, - value: PropTypes.string.isRequired, - isRefined: PropTypes.bool.isRequired, - noRefinement: PropTypes.bool.isRequired, - }) - ).isRequired, - canRefine: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - translate: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - renderItem = (item) => { - const { refine, translate } = this.props; - - return ( - - ); - }; - - render() { - const { items, canRefine, className } = this.props; - - return ( - ({ ...item, key: item.value }))} - className={className} - /> - ); - } -} - -export default translatable({ - all: 'All', -})(NumericMenu); diff --git a/packages/react-instantsearch-dom/src/components/Pagination.js b/packages/react-instantsearch-dom/src/components/Pagination.js deleted file mode 100644 index 3a08a29f9f..0000000000 --- a/packages/react-instantsearch-dom/src/components/Pagination.js +++ /dev/null @@ -1,194 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames, capitalize, range } from '../core/utils'; - -import LinkList from './LinkList'; - -const cx = createClassNames('Pagination'); - -// Determines the size of the widget (the number of pages displayed - that the user can directly click on) -function calculateSize(padding, maxPages) { - return Math.min(2 * padding + 1, maxPages); -} - -function calculatePaddingLeft(currentPage, padding, maxPages, size) { - if (currentPage <= padding) { - return currentPage; - } - - if (currentPage >= maxPages - padding) { - return size - (maxPages - currentPage); - } - - return padding + 1; -} - -// Retrieve the correct page range to populate the widget -function getPages(currentPage, maxPages, padding) { - const size = calculateSize(padding, maxPages); - // If the widget size is equal to the max number of pages, return the entire page range - if (size === maxPages) return range({ start: 1, end: maxPages + 1 }); - - const paddingLeft = calculatePaddingLeft( - currentPage, - padding, - maxPages, - size - ); - const paddingRight = size - paddingLeft; - - const first = currentPage - paddingLeft; - const last = currentPage + paddingRight; - return range({ start: first + 1, end: last + 1 }); -} - -class Pagination extends Component { - static propTypes = { - nbPages: PropTypes.number.isRequired, - currentRefinement: PropTypes.number.isRequired, - refine: PropTypes.func.isRequired, - createURL: PropTypes.func.isRequired, - canRefine: PropTypes.bool.isRequired, - - translate: PropTypes.func.isRequired, - listComponent: PropTypes.func, - - showFirst: PropTypes.bool, - showPrevious: PropTypes.bool, - showNext: PropTypes.bool, - showLast: PropTypes.bool, - padding: PropTypes.number, - totalPages: PropTypes.number, - className: PropTypes.string, - }; - - static defaultProps = { - listComponent: LinkList, - showFirst: true, - showPrevious: true, - showNext: true, - showLast: false, - padding: 3, - totalPages: Infinity, - className: '', - }; - - getItem(modifier, translationKey, value) { - const { nbPages, totalPages, translate } = this.props; - return { - key: `${modifier}.${value}`, - modifier, - disabled: value < 1 || value >= Math.min(totalPages, nbPages), - label: translate(translationKey, value), - value, - ariaLabel: translate(`aria${capitalize(translationKey)}`, value), - }; - } - - render() { - const { - listComponent: ListComponent, - nbPages, - totalPages, - currentRefinement, - padding, - showFirst, - showPrevious, - showNext, - showLast, - refine, - createURL, - canRefine, - translate, - className, - ...otherProps - } = this.props; - - const maxPages = Math.min(nbPages, totalPages); - const lastPage = maxPages; - - let items = []; - if (showFirst) { - items.push({ - key: 'first', - modifier: 'item--firstPage', - disabled: currentRefinement === 1, - label: translate('first'), - value: 1, - ariaLabel: translate('ariaFirst'), - }); - } - if (showPrevious) { - items.push({ - key: 'previous', - modifier: 'item--previousPage', - disabled: currentRefinement === 1, - label: translate('previous'), - value: currentRefinement - 1, - ariaLabel: translate('ariaPrevious'), - }); - } - - items = items.concat( - getPages(currentRefinement, maxPages, padding).map((value) => ({ - key: value, - modifier: 'item--page', - label: translate('page', value), - value, - selected: value === currentRefinement, - ariaLabel: translate('ariaPage', value), - })) - ); - if (showNext) { - items.push({ - key: 'next', - modifier: 'item--nextPage', - disabled: currentRefinement === lastPage || lastPage <= 1, - label: translate('next'), - value: currentRefinement + 1, - ariaLabel: translate('ariaNext'), - }); - } - if (showLast) { - items.push({ - key: 'last', - modifier: 'item--lastPage', - disabled: currentRefinement === lastPage || lastPage <= 1, - label: translate('last'), - value: lastPage, - ariaLabel: translate('ariaLast'), - }); - } - - return ( -
    - -
    - ); - } -} - -export default translatable({ - previous: '‹', - next: '›', - first: '«', - last: '»', - page: (currentRefinement) => currentRefinement.toString(), - ariaPrevious: 'Previous page', - ariaNext: 'Next page', - ariaFirst: 'First page', - ariaLast: 'Last page', - ariaPage: (currentRefinement) => `Page ${currentRefinement.toString()}`, -})(Pagination); diff --git a/packages/react-instantsearch-dom/src/components/Panel.js b/packages/react-instantsearch-dom/src/components/Panel.js deleted file mode 100644 index 9b2c4906b1..0000000000 --- a/packages/react-instantsearch-dom/src/components/Panel.js +++ /dev/null @@ -1,54 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component, createContext } from 'react'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('Panel'); - -export const { Consumer: PanelConsumer, Provider: PanelProvider } = - createContext(function setCanRefine() {}); - -class Panel extends Component { - static propTypes = { - children: PropTypes.node.isRequired, - className: PropTypes.string, - header: PropTypes.node, - footer: PropTypes.node, - }; - - static defaultProps = { - className: '', - header: null, - footer: null, - }; - - state = { - canRefine: true, - }; - - setCanRefine = (nextCanRefine) => { - this.setState({ canRefine: nextCanRefine }); - }; - - render() { - const { children, className, header, footer } = this.props; - const { canRefine } = this.state; - - return ( -
    - {header &&
    {header}
    } - -
    - {children} -
    - - {footer &&
    {footer}
    } -
    - ); - } -} - -export default Panel; diff --git a/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.d.ts b/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.d.ts deleted file mode 100644 index 04cca097e8..0000000000 --- a/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type React from 'react'; - -export default function PanelCallbackHandler(props: { - canRefine?: boolean; - children: React.reactNode; -}): JSX.Element; diff --git a/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.js b/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.js deleted file mode 100644 index 1201223e6b..0000000000 --- a/packages/react-instantsearch-dom/src/components/PanelCallbackHandler.js +++ /dev/null @@ -1,43 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import { PanelConsumer } from './Panel'; - -class PanelCallbackHandler extends Component { - static propTypes = { - children: PropTypes.node.isRequired, - canRefine: PropTypes.bool.isRequired, - setCanRefine: PropTypes.func.isRequired, - }; - - componentDidMount() { - this.props.setCanRefine(this.props.canRefine); - } - - componentDidUpdate(prevProps) { - if (prevProps.canRefine !== this.props.canRefine) { - this.props.setCanRefine(this.props.canRefine); - } - } - - render() { - return this.props.children; - } -} - -const PanelWrapper = ({ canRefine, children }) => ( - - {(setCanRefine) => ( - - {children} - - )} - -); - -PanelWrapper.propTypes = { - canRefine: PropTypes.bool.isRequired, - children: PropTypes.node.isRequired, -}; - -export default PanelWrapper; diff --git a/packages/react-instantsearch-dom/src/components/PoweredBy.js b/packages/react-instantsearch-dom/src/components/PoweredBy.js deleted file mode 100644 index d24009679b..0000000000 --- a/packages/react-instantsearch-dom/src/components/PoweredBy.js +++ /dev/null @@ -1,48 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('PoweredBy'); - -const AlgoliaLogo = () => ( - - - -); - -class PoweredBy extends Component { - static propTypes = { - url: PropTypes.string.isRequired, - translate: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - render() { - const { url, translate, className } = this.props; - - return ( -
    - {translate('searchBy')}{' '} - - - -
    - ); - } -} - -export default translatable({ - searchBy: 'Search by', -})(PoweredBy); diff --git a/packages/react-instantsearch-dom/src/components/QueryRuleCustomData.tsx b/packages/react-instantsearch-dom/src/components/QueryRuleCustomData.tsx deleted file mode 100644 index e1699fac3a..0000000000 --- a/packages/react-instantsearch-dom/src/components/QueryRuleCustomData.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import { createClassNames } from '../core/utils'; - -type CustomUserData = { - [key: string]: any; -}; - -const cx = createClassNames('QueryRuleCustomData'); - -type QueryRuleCustomDataRenderProps = { - items: TItem[]; -}; - -export type QueryRuleCustomDataProps = { - items: TItem[]; - className?: string; - children: (options: QueryRuleCustomDataRenderProps) => React.ReactNode; -}; - -const QueryRuleCustomData: React.FC> = - ({ items, className, children }) => ( -
    {children({ items })}
    - ); - -QueryRuleCustomData.propTypes = { - items: PropTypes.arrayOf(PropTypes.object).isRequired as any, - className: PropTypes.string, - children: PropTypes.func.isRequired, -}; - -export default QueryRuleCustomData; diff --git a/packages/react-instantsearch-dom/src/components/RangeInput.js b/packages/react-instantsearch-dom/src/components/RangeInput.js deleted file mode 100644 index 7fdfc5a50d..0000000000 --- a/packages/react-instantsearch-dom/src/components/RangeInput.js +++ /dev/null @@ -1,127 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('RangeInput'); - -export class RawRangeInput extends Component { - static propTypes = { - canRefine: PropTypes.bool.isRequired, - precision: PropTypes.number.isRequired, - translate: PropTypes.func.isRequired, - refine: PropTypes.func.isRequired, - min: PropTypes.number, - max: PropTypes.number, - currentRefinement: PropTypes.shape({ - min: PropTypes.number, - max: PropTypes.number, - }), - className: PropTypes.string, - }; - - static defaultProps = { - currentRefinement: {}, - className: '', - }; - - constructor(props) { - super(props); - - this.state = this.normalizeStateForRendering(props); - } - - componentDidUpdate(prevProps) { - if ( - this.props.canRefine && - (prevProps.currentRefinement.min !== this.props.currentRefinement.min || - prevProps.currentRefinement.max !== this.props.currentRefinement.max) - ) { - this.setState(this.normalizeStateForRendering(this.props)); - } - } - - onSubmit = (e) => { - e.preventDefault(); - - this.props.refine({ - min: this.state.from, - max: this.state.to, - }); - }; - - normalizeStateForRendering(props) { - const { canRefine, min: rangeMin, max: rangeMax } = props; - const { min: valueMin, max: valueMax } = props.currentRefinement; - - return { - from: - canRefine && valueMin !== undefined && valueMin !== rangeMin - ? valueMin - : '', - to: - canRefine && valueMax !== undefined && valueMax !== rangeMax - ? valueMax - : '', - }; - } - - normalizeRangeForRendering({ canRefine, min, max }) { - const hasMin = min !== undefined; - const hasMax = max !== undefined; - - return { - min: canRefine && hasMin && hasMax ? min : '', - max: canRefine && hasMin && hasMax ? max : '', - }; - } - - render() { - const { from, to } = this.state; - const { precision, translate, canRefine, className } = this.props; - const { min, max } = this.normalizeRangeForRendering(this.props); - const step = 1 / Math.pow(10, precision); - - return ( -
    -
    - this.setState({ from: e.currentTarget.value })} - /> - {translate('separator')} - this.setState({ to: e.currentTarget.value })} - /> - -
    -
    - ); - } -} - -export default translatable({ - submit: 'ok', - separator: 'to', -})(RawRangeInput); diff --git a/packages/react-instantsearch-dom/src/components/RatingMenu.js b/packages/react-instantsearch-dom/src/components/RatingMenu.js deleted file mode 100644 index c8011c3dc0..0000000000 --- a/packages/react-instantsearch-dom/src/components/RatingMenu.js +++ /dev/null @@ -1,188 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames, find, range } from '../core/utils'; - -const cx = createClassNames('RatingMenu'); - -class RatingMenu extends Component { - static propTypes = { - translate: PropTypes.func.isRequired, - refine: PropTypes.func.isRequired, - createURL: PropTypes.func.isRequired, - min: PropTypes.number, - max: PropTypes.number, - currentRefinement: PropTypes.shape({ - min: PropTypes.number, - max: PropTypes.number, - }), - count: PropTypes.arrayOf( - PropTypes.shape({ - value: PropTypes.string, - count: PropTypes.number, - }) - ), - canRefine: PropTypes.bool.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - onClick(min, max, e) { - e.preventDefault(); - e.stopPropagation(); - if ( - min === this.props.currentRefinement.min && - max === this.props.currentRefinement.max - ) { - this.props.refine({ min: this.props.min, max: this.props.max }); - } else { - this.props.refine({ min, max }); - } - } - - buildItem({ - max, - lowerBound, - count, - translate, - createURL, - isLastSelectableItem, - }) { - const disabled = !count; - const isCurrentMinLower = this.props.currentRefinement.min < lowerBound; - const selected = - (isLastSelectableItem && isCurrentMinLower) || - (!disabled && - lowerBound === this.props.currentRefinement.min && - max === this.props.currentRefinement.max); - - const icons = []; - let rating = 0; - for (let icon = 0; icon < max; icon++) { - if (icon < lowerBound) { - rating++; - } - icons.push([ - = lowerBound ? 'starIcon--empty' : 'starIcon--full' - )} - aria-hidden="true" - width="24" - height="24" - > - = lowerBound ? 'starEmptySymbol' : 'starSymbol' - )}`} - /> - , - ' ', - ]); - } - - // The last item of the list (the default item), should not - // be clickable if it is selected. - const isLastAndSelect = isLastSelectableItem && selected; - const onClickHandler = - disabled || isLastAndSelect - ? {} - : { - href: createURL({ min: lowerBound, max }), - onClick: this.onClick.bind(this, lowerBound, max), - }; - - return ( -
  • - - {icons} - {' '} - {count} - -
  • - ); - } - - render() { - const { min, max, translate, count, createURL, canRefine, className } = - this.props; - - // min & max are always set when there is a results, otherwise it means - // that we don't want to render anything since we don't have any values. - const limitMin = min !== undefined && min >= 0 ? min : 1; - const limitMax = max !== undefined && max >= 0 ? max : 0; - const inclusiveLength = limitMax - limitMin + 1; - - const values = count - .map((item) => ({ ...item, value: parseFloat(item.value) })) - .filter((item) => item.value >= limitMin && item.value <= limitMax); - - const items = range({ start: 0, end: Math.max(inclusiveLength, 0) }) - .map((index) => { - const element = find(values, (item) => item.value === limitMax - index); - const placeholder = { value: limitMax - index, count: 0, total: 0 }; - - return element || placeholder; - }) - .reduce( - (acc, item, index) => - acc.concat({ - ...item, - total: index === 0 ? item.count : acc[index - 1].total + item.count, - }), - [] - ) - .map((item, index, arr) => - this.buildItem({ - lowerBound: item.value, - count: item.total, - isLastSelectableItem: arr.length - 1 === index, - max: limitMax, - translate, - createURL, - }) - ); - - return ( -
    - - - - - - - - -
      - {items} -
    -
    - ); - } -} - -export default translatable({ - ratingLabel: ' & Up', -})(RatingMenu); diff --git a/packages/react-instantsearch-dom/src/components/RefinementList.js b/packages/react-instantsearch-dom/src/components/RefinementList.js deleted file mode 100644 index 3557517073..0000000000 --- a/packages/react-instantsearch-dom/src/components/RefinementList.js +++ /dev/null @@ -1,112 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; -import Highlight from '../widgets/Highlight'; - -import List from './List'; - -const cx = createClassNames('RefinementList'); - -class RefinementList extends Component { - static propTypes = { - translate: PropTypes.func.isRequired, - refine: PropTypes.func.isRequired, - searchForItems: PropTypes.func.isRequired, - searchable: PropTypes.bool, - createURL: PropTypes.func.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string.isRequired, - value: PropTypes.arrayOf(PropTypes.string).isRequired, - count: PropTypes.number.isRequired, - isRefined: PropTypes.bool.isRequired, - }) - ), - isFromSearch: PropTypes.bool.isRequired, - canRefine: PropTypes.bool.isRequired, - showMore: PropTypes.bool, - limit: PropTypes.number, - showMoreLimit: PropTypes.number, - transformItems: PropTypes.func, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - state = { - query: '', - }; - - selectItem = (item, resetQuery) => { - resetQuery(); - this.props.refine(item.value); - }; - - renderItem = (item, resetQuery) => { - const label = this.props.isFromSearch ? ( - - ) : ( - item.label - ); - - return ( - - ); - }; - - render() { - const { - translate, - items, - showMore, - limit, - showMoreLimit, - isFromSearch, - searchForItems, - searchable, - canRefine, - className, - } = this.props; - return ( - - ); - } -} - -export default translatable({ - showMore: (extended) => (extended ? 'Show less' : 'Show more'), - noResults: 'No results', - submit: null, - reset: null, - resetTitle: 'Clear the search query.', - submitTitle: 'Submit your search query.', - placeholder: 'Search here…', -})(RefinementList); diff --git a/packages/react-instantsearch-dom/src/components/RelevantSort.tsx b/packages/react-instantsearch-dom/src/components/RelevantSort.tsx deleted file mode 100644 index ff691f5fc6..0000000000 --- a/packages/react-instantsearch-dom/src/components/RelevantSort.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('RelevantSort'); - -export type RelevantSortComponentProps = { - isRelevantSorted: boolean; -}; - -export type RelevantSortProps = { - className?: string; - isVirtualReplica: boolean; - isRelevantSorted: boolean; - buttonTextComponent?: React.FunctionComponent; - textComponent?: React.FunctionComponent; - refine: (relevancyStrictness: number | undefined) => void; -}; - -const DefaultButtonTextComponent = ({ - isRelevantSorted, -}: RelevantSortComponentProps) => ( - {isRelevantSorted ? 'See all results' : 'See relevant results'} -); - -const RelevantSort: React.FC = ({ - className = '', - isVirtualReplica, - isRelevantSorted, - buttonTextComponent: ButtonTextComponent = DefaultButtonTextComponent, - textComponent: TextComponent, - refine, -}) => - !isVirtualReplica ? null : ( -
    -
    - {TextComponent && } -
    - -
    - ); - -RelevantSort.propTypes = { - buttonTextComponent: PropTypes.func, - className: PropTypes.string, - isVirtualReplica: PropTypes.bool.isRequired, - isRelevantSorted: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - textComponent: PropTypes.func, -}; - -export default RelevantSort; diff --git a/packages/react-instantsearch-dom/src/components/ScrollTo.js b/packages/react-instantsearch-dom/src/components/ScrollTo.js deleted file mode 100644 index f86189f3a6..0000000000 --- a/packages/react-instantsearch-dom/src/components/ScrollTo.js +++ /dev/null @@ -1,31 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('ScrollTo'); - -class ScrollTo extends Component { - static propTypes = { - value: PropTypes.any, - children: PropTypes.node, - hasNotChanged: PropTypes.bool, - }; - - componentDidUpdate(prevProps) { - const { value, hasNotChanged } = this.props; - if (value !== prevProps.value && hasNotChanged) { - this.el.scrollIntoView(); - } - } - - render() { - return ( -
    (this.el = ref)} className={cx('')}> - {this.props.children} -
    - ); - } -} - -export default ScrollTo; diff --git a/packages/react-instantsearch-dom/src/components/SearchBox.js b/packages/react-instantsearch-dom/src/components/SearchBox.js deleted file mode 100644 index 270bb34f62..0000000000 --- a/packages/react-instantsearch-dom/src/components/SearchBox.js +++ /dev/null @@ -1,316 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('SearchBox'); - -const defaultLoadingIndicator = ( - -); - -const defaultReset = ( - -); - -const defaultSubmit = ( - -); - -class SearchBox extends Component { - static propTypes = { - currentRefinement: PropTypes.string, - className: PropTypes.string, - refine: PropTypes.func.isRequired, - translate: PropTypes.func.isRequired, - - loadingIndicator: PropTypes.node, - reset: PropTypes.node, - submit: PropTypes.node, - - focusShortcuts: PropTypes.arrayOf( - PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - ), - - autoFocus: PropTypes.bool, - - searchAsYouType: PropTypes.bool, - onSubmit: PropTypes.func, - onReset: PropTypes.func, - onChange: PropTypes.func, - - isSearchStalled: PropTypes.bool, - showLoadingIndicator: PropTypes.bool, - - formRef: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.exact({ current: PropTypes.object }), - ]), - - inputRef: PropTypes.oneOfType([ - PropTypes.func, - PropTypes.exact({ current: PropTypes.object }), - ]), - inputId: PropTypes.string, - }; - - static defaultProps = { - currentRefinement: '', - className: '', - focusShortcuts: ['s', '/'], - autoFocus: false, - searchAsYouType: true, - showLoadingIndicator: false, - isSearchStalled: false, - loadingIndicator: defaultLoadingIndicator, - reset: defaultReset, - submit: defaultSubmit, - }; - - constructor(props) { - super(); - - this.state = { - query: props.searchAsYouType ? null : props.currentRefinement, - }; - } - - componentDidMount() { - document.addEventListener('keydown', this.onKeyDown); - } - - componentWillUnmount() { - document.removeEventListener('keydown', this.onKeyDown); - } - - componentDidUpdate(prevProps) { - if ( - !this.props.searchAsYouType && - prevProps.currentRefinement !== this.props.currentRefinement - ) { - this.setState({ - query: this.props.currentRefinement, - }); - } - } - - getQuery = () => - this.props.searchAsYouType - ? this.props.currentRefinement - : this.state.query; - - onInputMount = (input) => { - this.input = input; - if (!this.props.inputRef) return; - if (typeof this.props.inputRef === 'function') { - this.props.inputRef(input); - } else { - this.props.inputRef.current = input; - } - }; - - // From https://github.com/algolia/autocomplete.js/pull/86 - onKeyDown = (e) => { - if (!this.props.focusShortcuts) { - return; - } - - const shortcuts = this.props.focusShortcuts.map((key) => - typeof key === 'string' ? key.toUpperCase().charCodeAt(0) : key - ); - - const elt = e.target || e.srcElement; - const tagName = elt.tagName; - if ( - elt.isContentEditable || - tagName === 'INPUT' || - tagName === 'SELECT' || - tagName === 'TEXTAREA' - ) { - // already in an input - return; - } - - const which = e.which || e.keyCode; - if (shortcuts.indexOf(which) === -1) { - // not the right shortcut - return; - } - - this.input.focus(); - e.stopPropagation(); - e.preventDefault(); - }; - - onSubmit = (e) => { - e.preventDefault(); - e.stopPropagation(); - this.input.blur(); - - const { refine, searchAsYouType } = this.props; - if (!searchAsYouType) { - refine(this.getQuery()); - } - return false; - }; - - onChange = (event) => { - const { searchAsYouType, refine, onChange } = this.props; - const value = event.target.value; - - if (searchAsYouType) { - refine(value); - } else { - this.setState({ query: value }); - } - - if (onChange) { - onChange(event); - } - }; - - onReset = (event) => { - const { searchAsYouType, refine, onReset } = this.props; - - refine(''); - this.input.focus(); - - if (!searchAsYouType) { - this.setState({ query: '' }); - } - - if (onReset) { - onReset(event); - } - }; - - render() { - const { - className, - inputId, - translate, - autoFocus, - loadingIndicator, - submit, - reset, - } = this.props; - const query = this.getQuery(); - - const searchInputEvents = Object.keys(this.props).reduce((props, prop) => { - if ( - ['onsubmit', 'onreset', 'onchange'].indexOf(prop.toLowerCase()) === - -1 && - prop.indexOf('on') === 0 - ) { - return { ...props, [prop]: this.props[prop] }; - } - - return props; - }, {}); - - const isSearchStalled = - this.props.showLoadingIndicator && this.props.isSearchStalled; - - return ( -
    -
    - - - - {this.props.showLoadingIndicator && ( - - )} -
    -
    - ); - } -} - -export default translatable({ - resetTitle: 'Clear the search query.', - submitTitle: 'Submit your search query.', - placeholder: 'Search here…', -})(SearchBox); diff --git a/packages/react-instantsearch-dom/src/components/Select.js b/packages/react-instantsearch-dom/src/components/Select.js deleted file mode 100644 index 81b831eadf..0000000000 --- a/packages/react-instantsearch-dom/src/components/Select.js +++ /dev/null @@ -1,50 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -export default class Select extends Component { - static propTypes = { - cx: PropTypes.func.isRequired, - id: PropTypes.string, - onSelect: PropTypes.func.isRequired, - items: PropTypes.arrayOf( - PropTypes.shape({ - value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - - key: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - label: PropTypes.string, - disabled: PropTypes.bool, - }) - ).isRequired, - selectedItem: PropTypes.oneOfType([PropTypes.string, PropTypes.number]) - .isRequired, - }; - - onChange = (e) => { - this.props.onSelect(e.target.value); - }; - - render() { - const { cx, id, items, selectedItem } = this.props; - - return ( - - ); - } -} diff --git a/packages/react-instantsearch-dom/src/components/Snippet.js b/packages/react-instantsearch-dom/src/components/Snippet.js deleted file mode 100644 index f5287d99e0..0000000000 --- a/packages/react-instantsearch-dom/src/components/Snippet.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; - -import { createClassNames } from '../core/utils'; - -import Highlighter from './Highlighter'; - -const cx = createClassNames('Snippet'); - -const Snippet = (props) => ( - -); - -export default Snippet; diff --git a/packages/react-instantsearch-dom/src/components/SortBy.js b/packages/react-instantsearch-dom/src/components/SortBy.js deleted file mode 100644 index 7d05023617..0000000000 --- a/packages/react-instantsearch-dom/src/components/SortBy.js +++ /dev/null @@ -1,46 +0,0 @@ -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import { createClassNames } from '../core/utils'; - -import Select from './Select'; - -const cx = createClassNames('SortBy'); - -class SortBy extends Component { - static propTypes = { - id: PropTypes.string, - items: PropTypes.arrayOf( - PropTypes.shape({ - label: PropTypes.string, - value: PropTypes.string.isRequired, - }) - ).isRequired, - currentRefinement: PropTypes.string.isRequired, - refine: PropTypes.func.isRequired, - className: PropTypes.string, - }; - - static defaultProps = { - className: '', - }; - - render() { - const { id, items, currentRefinement, refine, className } = this.props; - - return ( -
    - refine(event.target.checked)} - /> - {label} - -
    -); - -ToggleRefinement.propTypes = { - currentRefinement: PropTypes.bool.isRequired, - label: PropTypes.string.isRequired, - canRefine: PropTypes.bool.isRequired, - refine: PropTypes.func.isRequired, - className: PropTypes.string, -}; - -ToggleRefinement.defaultProps = { - className: '', -}; - -export default ToggleRefinement; diff --git a/packages/react-instantsearch-dom/src/components/VoiceSearch.tsx b/packages/react-instantsearch-dom/src/components/VoiceSearch.tsx deleted file mode 100644 index b9fba7b732..0000000000 --- a/packages/react-instantsearch-dom/src/components/VoiceSearch.tsx +++ /dev/null @@ -1,170 +0,0 @@ -import React, { Component } from 'react'; -import { translatable } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; -import createVoiceSearchHelper from '../lib/voiceSearchHelper'; - -import type { - VoiceSearchHelper, - VoiceListeningState, - Status, - SpeechRecognitionErrorCode, -} from '../lib/voiceSearchHelper'; -const cx = createClassNames('VoiceSearch'); - -type ButtonSvgProps = { - children: React.ReactNode; -}; - -export type InnerComponentProps = { - status: Status; - errorCode?: SpeechRecognitionErrorCode; - isListening: boolean; - transcript: string; - isSpeechFinal: boolean; - isBrowserSupported: boolean; -}; - -type Translate = (key: string, ...params: any[]) => string; - -type VoiceSearchProps = { - searchAsYouSpeak: boolean; - language?: string; - additionalQueryParameters?: (params: { query: string }) => {} | void; - - refine: (query: string) => void; - translate: Translate; - buttonTextComponent: React.FC; - statusComponent: React.FC; -}; - -const ButtonSvg = ({ children }: ButtonSvgProps) => ( - - {children} - -); - -const DefaultButtonText = ({ - status, - errorCode, - isListening, -}: InnerComponentProps) => { - return status === 'error' && errorCode === 'not-allowed' ? ( - - - - - - - - ) : ( - - - - - - - ); -}; - -const DefaultStatus = ({ transcript }: InnerComponentProps) => ( -

    {transcript}

    -); - -class VoiceSearch extends Component { - protected static defaultProps = { - searchAsYouSpeak: false, - buttonTextComponent: DefaultButtonText, - statusComponent: DefaultStatus, - }; - private voiceSearchHelper?: VoiceSearchHelper; - - public componentDidMount() { - const { searchAsYouSpeak = false, language, refine } = this.props; - this.voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak, - language, - onQueryChange: (query) => refine(query), - onStateChange: () => { - this.setState(this.voiceSearchHelper!.getState()); - }, - }); - this.setState(this.voiceSearchHelper.getState()); - } - - public render() { - if (!this.voiceSearchHelper) { - return null; - } - - const { status, transcript, isSpeechFinal, errorCode } = this.state; - const { isListening, isBrowserSupported } = this.voiceSearchHelper; - const { - translate, - buttonTextComponent: ButtonTextComponent, - statusComponent: StatusComponent, - } = this.props; - const innerProps: InnerComponentProps = { - status, - errorCode, - isListening: isListening(), - transcript, - isSpeechFinal, - isBrowserSupported: isBrowserSupported(), - }; - - return ( -
    - -
    - -
    -
    - ); - } - - public componentWillUnmount() { - if (this.voiceSearchHelper) { - this.voiceSearchHelper.dispose(); - } - } - - private onClick = (event: React.MouseEvent) => { - if (!this.voiceSearchHelper) { - return; - } - event.currentTarget.blur(); - const { toggleListening } = this.voiceSearchHelper; - toggleListening(); - }; -} - -export default translatable({ - buttonTitle: 'Search by voice', - disabledButtonTitle: 'Search by voice (not supported on this browser)', -})(VoiceSearch); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Breadcrumb.js b/packages/react-instantsearch-dom/src/components/__tests__/Breadcrumb.js deleted file mode 100644 index df144fcf54..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Breadcrumb.js +++ /dev/null @@ -1,239 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Breadcrumb from '../Breadcrumb'; -import Link from '../Link'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Breadcrumb', () => { - it('outputs the default breadcrumb', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('outputs the default breadcrumb with no refinement', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={false} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('outputs the default breadcrumb with a custom className', () => { - const tree = renderer.create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ); - - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ); - - const breadcrumb = wrapper.find('ul'); - - expect(breadcrumb.children()).toHaveLength(4); - - breadcrumb.children().first().find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual(); - - breadcrumb.children().at(1).find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(2); - expect(refine.mock.calls[1][0]).toEqual('white'); - - breadcrumb.children().at(2).find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(3); - expect(refine.mock.calls[2][0]).toEqual('white > white1'); - - const lastItem = breadcrumb.children().at(3).find(Link); - - expect(lastItem).toHaveLength(0); - - wrapper.unmount(); - }); - - it('has a rootURL prop', () => { - const refine = jest.fn(); - const rootLink = 'www.algolia.com'; - - const wrapper = mount( - '#'} - rootURL={rootLink} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ); - - const breadcrumb = wrapper.find('ul'); - - expect(breadcrumb.children()).toHaveLength(4); - - breadcrumb.children().first().find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(0); - expect(wrapper.find('a').first().prop('href')).toEqual('www.algolia.com'); - - wrapper.unmount(); - }); - - it('has a separator prop that can be a custom component', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - separator={🔍} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('has customizable translations', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - translations={{ - rootLabel: 'ROOT_LABEL', - }} - items={[ - { - value: 'white', - label: 'white', - }, - { - value: 'white > white1', - label: 'white1', - }, - { - value: 'white > white1 > white1.1', - label: 'white1.1', - }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/ClearRefinements.js b/packages/react-instantsearch-dom/src/components/__tests__/ClearRefinements.js deleted file mode 100644 index 7e27ab8c8d..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/ClearRefinements.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import ClearRefinements from '../ClearRefinements'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('ClearRefinements', () => { - it('renders a clickable button', () => - expect( - renderer - .create( - null} - /> - ) - .toJSON() - ).toMatchSnapshot()); - - it('renders a clickable button with a custom className', () => - expect( - renderer - .create( - null} - /> - ) - .toJSON() - ).toMatchSnapshot()); - - it('has a disabled mode', () => - expect( - renderer - .create( - null} /> - ) - .toJSON() - ).toMatchSnapshot()); - - it('is disabled when there is no filters', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - expect(refine.mock.calls).toHaveLength(0); - wrapper.find('button').simulate('click'); - expect(refine.mock.calls).toHaveLength(0); - }); - - it('is not disabled when there are filters', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - expect(refine.mock.calls).toHaveLength(0); - wrapper.find('button').simulate('click'); - expect(refine.mock.calls).toHaveLength(1); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/CurrentRefinements.js b/packages/react-instantsearch-dom/src/components/__tests__/CurrentRefinements.js deleted file mode 100644 index 0c99707f03..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/CurrentRefinements.js +++ /dev/null @@ -1,154 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import Connected, { CurrentRefinements } from '../CurrentRefinements'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('CurrentRefinements', () => { - const defaultProps = { - items: [], - canRefine: true, - refine: () => {}, - translate: (x) => x, - }; - - it('expect to render a list of current refinements', () => { - const props = { - ...defaultProps, - items: [ - { label: 'color: Red', value: () => {} }, - { - label: 'category:', - value: () => {}, - items: [ - { label: 'iPhone', value: () => {} }, - { label: 'iPad', value: () => {} }, - ], - }, - ], - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render a list without refinements', () => { - const props = { - ...defaultProps, - canRefine: false, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render a list with a custom className', () => { - const props = { - ...defaultProps, - className: 'MyCustomCurrentRefinements', - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to refine the "color" onClick', () => { - const value = () => {}; - const props = { - ...defaultProps, - items: [ - { label: 'color: Red', value }, - { - label: 'category:', - value: () => {}, - items: [ - { label: 'iPhone', value: () => {} }, - { label: 'iPad', value: () => {} }, - ], - }, - ], - refine: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.refine).not.toHaveBeenCalled(); - - wrapper.find('li').first().find('button').simulate('click'); - - expect(props.refine).toHaveBeenCalledWith(value); - }); - - it('expect to refine the "category: iPad" onClick', () => { - const value = () => {}; - const props = { - ...defaultProps, - items: [ - { label: 'color: Red', value: () => {} }, - { - label: 'category:', - value: () => {}, - items: [ - { label: 'iPhone', value: () => {} }, - { label: 'iPad', value }, - ], - }, - ], - refine: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.refine).not.toHaveBeenCalled(); - - wrapper.find('li').last().find('button').last().simulate('click'); - - expect(props.refine).toHaveBeenCalledWith(value); - }); -}); - -describe('CurrentRefinements - Connected', () => { - const defaultProps = { - items: [ - { label: 'color: Red', value: () => {} }, - { - label: 'category:', - value: () => {}, - items: [ - { label: 'iPhone', value: () => {} }, - { label: 'iPad', value: () => {} }, - ], - }, - ], - canRefine: true, - refine: () => {}, - }; - - it('expect to render a list of current refinements', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow().dive(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render a list of current refinements with custom translations', () => { - const props = { - ...defaultProps, - translations: { - clearFilter: 'DELETE', - }, - }; - - const wrapper = shallow().dive(); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/HierarchicalMenu.js b/packages/react-instantsearch-dom/src/components/__tests__/HierarchicalMenu.js deleted file mode 100644 index 01cfe3071a..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/HierarchicalMenu.js +++ /dev/null @@ -1,194 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import HierarchicalMenu from '../HierarchicalMenu'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('HierarchicalMenu', () => { - it('default hierarchical menu', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - count: 10, - label: 'white', - items: [ - { value: 'white1', label: 'white1', count: 3 }, - { value: 'white2', label: 'white2', count: 4 }, - ], - }, - { value: 'black', isRefined: true, count: 20, label: 'black' }, - { value: 'blue', count: 30, label: 'blue' }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default hierarchical menu with a custom className', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - count: 10, - label: 'white', - items: [ - { value: 'white1', label: 'white1', count: 3 }, - { value: 'white2', label: 'white2', count: 4 }, - ], - }, - { value: 'black', count: 20, label: 'black' }, - { value: 'blue', count: 30, label: 'blue' }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - canRefine={true} - /> - ) - .toJSON(); - - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - items={[ - { - value: 'white', - count: 10, - label: 'white', - items: [ - { value: 'white1', label: 'white1', count: 3 }, - { value: 'white2', label: 'white2', count: 4 }, - ], - }, - { value: 'black', count: 20, label: 'black' }, - { value: 'blue', count: 30, label: 'blue' }, - ]} - translations={{ - showMore: ' display more', - }} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { - value: 'white', - count: 10, - label: 'white', - items: [ - { value: 'white1', label: 'white1', count: 3 }, - { value: 'white2', label: 'white2', count: 4 }, - ], - }, - { value: 'black', count: 20, label: 'black' }, - { value: 'blue', count: 30, label: 'blue' }, - ]} - canRefine={true} - /> - ); - - const itemParent = wrapper.find('.ais-HierarchicalMenu-item--parent'); - - expect(itemParent).toHaveLength(1); - - itemParent.find('Link').first().simulate('click'); - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('white'); - - wrapper.unmount(); - }); - - it('should respect defined limits', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { value: 'white', count: 10, label: 'white' }, - { value: 'black', count: 20, label: 'black' }, - { value: 'blue', count: 30, label: 'blue' }, - { value: 'green', count: 30, label: 'green' }, - { value: 'cyan', count: 30, label: 'cyan' }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - wrapper.find('button').simulate('click'); - - expect(wrapper.find('li')).toHaveLength(4); - - wrapper.unmount(); - }); - - it('should disabled show more when no more item to display', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { value: 'white', count: 10, label: 'white' }, - { value: 'black', count: 20, label: 'black' }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - expect(wrapper.find('button')).toBeDefined(); - - wrapper.unmount(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Highlight.js b/packages/react-instantsearch-dom/src/components/__tests__/Highlight.js deleted file mode 100644 index 36451674ee..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Highlight.js +++ /dev/null @@ -1,123 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Highlight from '../Highlight'; - -describe('Highlight', () => { - it('parses an highlighted attribute of hit object', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _highlightResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('renders a hit with a custom tag correctly', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _highlightResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - tagName="marquee" - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('renders a hit with a custom className', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _highlightResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - className="MyCustomHighlight" - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - /> - ); - - expect(tree.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Highlighter.js b/packages/react-instantsearch-dom/src/components/__tests__/Highlighter.js deleted file mode 100644 index 4ab4a9606d..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Highlighter.js +++ /dev/null @@ -1,312 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import Highlighter, { Highlight } from '../Highlighter'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('Highlighter - Highlight', () => { - const defaultProps = { - value: 'test', - highlightedTagName: 'em', - isHighlighted: false, - nonHighlightedTagName: 'div', - }; - - it('renders a highlight', () => { - const props = { - ...defaultProps, - isHighlighted: true, - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a nonhighlight', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); -}); - -describe('Highlighter - simple', () => { - const hitFromAPI = { - objectID: 3, - title: 'Apple', - _highlight: { - title: { - value: 'Apple', - }, - }, - }; - - const defaultProps = { - hit: hitFromAPI, - attribute: 'title', - highlightProperty: '_highlight', - }; - - it('renders a highlighted value', () => { - const props = { - ...defaultProps, - highlight: () => [ - { value: 'Ap', isHighlighted: true }, - { value: 'ple', isHighlighted: false }, - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a non highlighted value', () => { - const props = { - ...defaultProps, - hit: { - objectID: 3, - title: 'Apple', - _highlight: { - title: { - value: 'Apple', - }, - }, - }, - highlight: () => [{ value: 'Apple', isHighlighted: false }], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a highlighted value with a custom tagName', () => { - const props = { - ...defaultProps, - tagName: 'strong', - highlight: () => [ - { value: 'Ap', isHighlighted: true }, - { value: 'ple', isHighlighted: false }, - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a highlighted value with a custom nonHighlightedTagName', () => { - const props = { - ...defaultProps, - nonHighlightedTagName: 'p', - highlight: () => [ - { value: 'Ap', isHighlighted: true }, - { value: 'ple', isHighlighted: false }, - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders with a custom className', () => { - const props = { - ...defaultProps, - className: 'MyCustomHighlighter', - highlight: () => [ - { value: 'Ap', isHighlighted: true }, - { value: 'ple', isHighlighted: false }, - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); -}); - -describe('Highlighter - multi', () => { - const hitFromAPI = { - objectID: 3, - titles: ['Apple', 'Samsung', 'Philips'], - _highlight: { - titles: [ - { - value: 'Apple', - }, - { - value: 'Samsung', - }, - { - value: 'Philips', - }, - ], - }, - }; - - const defaultProps = { - hit: hitFromAPI, - attribute: 'titles', - highlightProperty: '_highlight', - }; - - it('renders a highlighted value', () => { - const props = { - ...defaultProps, - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [ - { value: 'Sam', isHighlighted: true }, - { value: 'sung', isHighlighted: false }, - ], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a non highlighted value', () => { - const props = { - ...defaultProps, - hit: { - objectID: 3, - titles: ['Apple', 'Samsung', 'Philips'], - _highlight: { - titles: [ - { - value: 'Apple', - }, - { - value: 'Samsung', - }, - { - value: 'Philips', - }, - ], - }, - }, - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [{ value: 'Samsung', isHighlighted: false }], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a highlighted value with a custom tagName', () => { - const props = { - ...defaultProps, - tagName: 'strong', - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [ - { value: 'Sam', isHighlighted: true }, - { value: 'sung', isHighlighted: false }, - ], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a highlighted value with a custom nonHighlightedTagName', () => { - const props = { - ...defaultProps, - nonHighlightedTagName: 'p', - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [ - { value: 'Sam', isHighlighted: true }, - { value: 'sung', isHighlighted: false }, - ], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a highlighted value with a custom separator', () => { - const props = { - ...defaultProps, - separator: '-', - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [ - { value: 'Sam', isHighlighted: true }, - { value: 'sung', isHighlighted: false }, - ], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('renders a custom className', () => { - const props = { - ...defaultProps, - className: 'MyCustomHighlighter', - highlight: () => [ - [{ value: 'Apple', isHighlighted: false }], - [ - { value: 'Sam', isHighlighted: true }, - { value: 'sung', isHighlighted: false }, - ], - [{ value: 'Philips', isHighlighted: false }], - ], - }; - - const wrapper = shallow( - x.join(' ')} {...props} /> - ); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Hits.tsx b/packages/react-instantsearch-dom/src/components/__tests__/Hits.tsx deleted file mode 100644 index 9f4cbb17f8..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Hits.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Hits from '../Hits'; - -describe('Hits', () => { - type Props = { hit: any }; - - const Hit = ({ hit }: Props) =>
    ; - - it('accepts a hitComponent prop', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - - const tree = renderer.create(); - - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('accepts a custom className', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - - const tree = renderer.create( - - ); - - expect(tree.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/HitsPerPage.js b/packages/react-instantsearch-dom/src/components/__tests__/HitsPerPage.js deleted file mode 100644 index 19799c8d5c..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/HitsPerPage.js +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import HitsPerPage from '../HitsPerPage'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('HitsPerPage', () => { - it('renders', () => - expect( - renderer - .create( - null} - currentRefinement={5} - items={[ - { - value: 5, - label: 'show 5 hits', - }, - { - value: 10, - label: 'show 10 hits', - }, - ]} - /> - ) - .toJSON() - ).toMatchSnapshot()); - - it('renders with a custom className', () => - expect( - renderer - .create( - null} - currentRefinement={5} - items={[ - { - value: 5, - label: 'show 5 hits', - }, - { - value: 10, - label: 'show 10 hits', - }, - ]} - /> - ) - .toJSON() - ).toMatchSnapshot()); - - it('should forward the id to Select', () => { - const id = 'ais-select'; - const wrapper = mount( - '#'} - items={[ - { value: 2, label: '2 hits per page' }, - { value: 4, label: '4 hits per page' }, - { value: 6, label: '6 hits per page' }, - { value: 8, label: '8 hits per page' }, - ]} - refine={() => null} - currentRefinement={2} - /> - ); - - const selectedValue = wrapper.find('select').getDOMNode(); - expect(selectedValue.getAttribute('id')).toEqual(id); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { value: 2, label: '2 hits per page' }, - { value: 4, label: '4 hits per page' }, - { value: 6, label: '6 hits per page' }, - { value: 8, label: '8 hits per page' }, - ]} - refine={refine} - currentRefinement={2} - /> - ); - - const selectedValue = wrapper.find('select'); - expect(selectedValue.find('option')).toHaveLength(4); - expect(selectedValue.find('option').first().text()).toBe('2 hits per page'); - - selectedValue.find('select').simulate('change', { target: { value: '6' } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('6'); - }); - - it('should use value if no label provided', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[{ value: 2 }, { value: 4 }, { value: 6 }, { value: 8 }]} - refine={refine} - currentRefinement={2} - /> - ); - - const selectedValue = wrapper.find('select'); - expect(selectedValue.find('option')).toHaveLength(4); - expect(selectedValue.find('option').first().text()).toBe('2'); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/InfiniteHits.js b/packages/react-instantsearch-dom/src/components/__tests__/InfiniteHits.js deleted file mode 100644 index 52256d35bd..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/InfiniteHits.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import PropTypes from 'prop-types'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import InfiniteHits from '../InfiniteHits'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('InfiniteHits', () => { - const Hit = ({ hit }) =>
    {JSON.stringify(hit)}
    ; - - Hit.propTypes = { - hit: PropTypes.object, - }; - - it('accepts a hitComponent prop', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const tree = renderer.create( - undefined} - refineNext={() => undefined} - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('accepts a custom className', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const tree = renderer.create( - undefined} - refineNext={() => undefined} - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('calls refineNext when the load more button is clicked', () => { - const mockedRefine = jest.fn(); - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const wrapped = mount( - undefined} - refineNext={mockedRefine} - hitComponent={Hit} - hits={hits} - hasMore={true} - hasPrevious={false} - /> - ); - expect(mockedRefine.mock.calls).toHaveLength(0); - wrapped.find('button').simulate('click'); - expect(mockedRefine.mock.calls).toHaveLength(1); - }); - - it('calls refinePrevious when the load previous button is clicked', () => { - const mockedRefinePrevious = jest.fn(); - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const wrapped = mount( - undefined} - hitComponent={Hit} - hits={hits} - hasMore={true} - hasPrevious={true} - /> - ); - expect(mockedRefinePrevious).toHaveBeenCalledTimes(0); - wrapped.find('.ais-InfiniteHits-loadPrevious').simulate('click'); - expect(mockedRefinePrevious).toHaveBeenCalledTimes(1); - }); - - it('render "Show previous" button depending of `showPrevious` prop', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const wrapped = mount( - undefined} - refineNext={() => undefined} - hitComponent={Hit} - hits={hits} - hasMore={false} - hasPrevious={false} - /> - ); - expect(wrapped.find('.ais-InfiniteHits-loadPrevious').length).toEqual(0); - - wrapped.setProps({ showPrevious: true }); - - expect(wrapped.find('.ais-InfiniteHits-loadPrevious').length).toEqual(1); - }); - - it('"Show more" button is disabled when it is the last page', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const wrapped = mount( - undefined} - refineNext={() => undefined} - hitComponent={Hit} - hits={hits} - hasMore={false} - hasPrevious={false} - /> - ); - expect(wrapped.find('.ais-InfiniteHits-loadMore').props().disabled).toBe( - true - ); - }); - - it('"Show previous" button is disabled when it is the first page', () => { - const hits = [{ objectID: 0 }, { objectID: 1 }, { objectID: 2 }]; - const wrapped = mount( - undefined} - refineNext={() => undefined} - hitComponent={Hit} - hits={hits} - hasMore={false} - hasPrevious={false} - /> - ); - expect( - wrapped.find('.ais-InfiniteHits-loadPrevious').props().disabled - ).toBe(true); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/List.js b/packages/react-instantsearch-dom/src/components/__tests__/List.js deleted file mode 100644 index 3d0d3da308..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/List.js +++ /dev/null @@ -1,148 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import List from '../List'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('List', () => { - const defaultProps = { - items: [], - canRefine: true, - renderItem: (item) => {item.value}, - cx: (...args) => args.filter(Boolean).join(' '), - }; - - const apple = { - label: 'Apple', - value: 'Apple', - count: 100, - isRefined: false, - }; - - const appleSubElements = [ - { - label: 'iPhone', - value: 'iPhone', - count: 50, - isRefined: false, - }, - { - label: 'iPad', - value: 'iPad', - count: 50, - isRefined: false, - }, - ]; - - const samsung = { - label: 'Samsung', - value: 'Samsung', - count: 50, - isRefined: false, - }; - - const samsungSubElements = [ - { - label: 'S8', - value: 'S8', - count: 25, - isRefined: false, - }, - { - label: 'Note 5', - value: 'Note 5', - count: 25, - isRefined: false, - }, - ]; - - const microsoft = { - label: 'Microsoft', - value: 'Microsoft', - count: 25, - isRefined: false, - }; - - const microsoftSubElements = [ - { - label: 'Surface', - value: 'Surface', - count: 13, - isRefined: false, - }, - { - label: 'Surface Pro', - value: 'Surface Pro', - count: 12, - isRefined: false, - }, - ]; - - it('expect to render a list of items', () => { - const props = { - ...defaultProps, - items: [apple, samsung, microsoft], - }; - - const wrapper = shallow(); - - expect(wrapper.find('.item')).toHaveLength(3); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render a list of nested items', () => { - const props = { - ...defaultProps, - items: [ - { - ...apple, - items: appleSubElements, - }, - { - ...samsung, - items: samsungSubElements, - }, - { - ...microsoft, - items: microsoftSubElements, - }, - ], - }; - - const wrapper = shallow(); - - expect(wrapper.find('.item')).toHaveLength(9); // 3 parents + (3 * 2 children) - expect(wrapper.find('.item--parent')).toHaveLength(3); - expect(wrapper.find('.list--child')).toHaveLength(3); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render a list of nested items with empty children', () => { - const props = { - ...defaultProps, - items: [ - { - ...apple, - items: appleSubElements, - }, - { - ...samsung, - items: samsungSubElements, - }, - microsoft, - ], - }; - - const wrapper = shallow(); - - expect(wrapper.find('.item')).toHaveLength(7); // 3 parents + (2 * 2 children) - expect(wrapper.find('.item--parent')).toHaveLength(2); - expect(wrapper.find('.list--child')).toHaveLength(2); - - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Menu.js b/packages/react-instantsearch-dom/src/components/__tests__/Menu.js deleted file mode 100644 index ed796d3835..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Menu.js +++ /dev/null @@ -1,320 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Link from '../Link'; -import Menu from '../Menu'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('../../widgets/Highlight', () => () => null); - -describe('Menu', () => { - it('default menu', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - createURL={() => '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default menu with custom className', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - createURL={() => '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('Menu with search inside items but no search results', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - searchable - createURL={() => '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: true }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - ]} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('Menu with search inside items with search results', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - searchable - createURL={() => '#'} - items={[ - { - label: 'white', - value: 'white', - count: 10, - isRefined: true, - _highlightResult: { label: 'white' }, - }, - ]} - isFromSearch={true} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - searchForItems={() => null} - searchable - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - translations={{ - showMore: ' display more', - placeholder: 'placeholder', - }} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - null} - createURL={() => '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - ]} - isFromSearch={false} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(3); - - const firstItem = items.first().find(Link); - - firstItem.simulate('click'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('white'); - - wrapper.unmount(); - }); - - it('should respect defined limits', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - searchForItems={() => null} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - wrapper.find('button').simulate('click'); - - expect(wrapper.find('li')).toHaveLength(4); - - wrapper.unmount(); - }); - - it('should disabled show more when no more item to display', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - searchForItems={() => null} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - expect(wrapper.find('button[disabled]')).toBeDefined(); - - wrapper.unmount(); - }); - - describe('search for facets value', () => { - const refine = jest.fn(); - const searchForItems = jest.fn(); - const menu = ( - '#'} - items={[ - { - label: 'white', - value: 'white', - count: 10, - isRefined: false, - _highlightResult: { label: { value: 'white' } }, - }, - { - label: 'black', - value: 'black', - count: 20, - isRefined: false, - _highlightResult: { label: { value: 'black' } }, - }, - ]} - isFromSearch={true} - canRefine={true} - /> - ); - - it('a searchbox should be displayed if the feature is activated', () => { - const wrapper = mount(menu); - - const searchBox = wrapper.find('.searchBox'); - - expect(searchBox).toBeDefined(); - - wrapper.unmount(); - }); - - it('searching for a value should call searchForItems', () => { - const wrapper = mount(menu); - - wrapper.find('input').simulate('change', { target: { value: 'query' } }); - - expect(searchForItems.mock.calls).toHaveLength(1); - expect(searchForItems.mock.calls[0][0]).toBe('query'); - - wrapper.unmount(); - }); - - it('should refine the selected value and display selected refinement back', () => { - const wrapper = mount(menu); - - const firstItem = wrapper.find('li').first().find(Link); - firstItem.simulate('click'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('white'); - expect(wrapper.find('input').props().value).toBe(''); - - const selectedRefinements = wrapper.find('li'); - expect(selectedRefinements).toHaveLength(2); - - wrapper.unmount(); - }); - - it('hit enter on the search values results list should refine the first facet value', () => { - refine.mockClear(); - const wrapper = mount(menu); - - wrapper.find('form').simulate('submit'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('white'); - expect(wrapper.find('input').props().value).toBe(''); - - const selectedRefinements = wrapper.find('li'); - expect(selectedRefinements).toHaveLength(2); - - wrapper.unmount(); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/MenuSelect.js b/packages/react-instantsearch-dom/src/components/__tests__/MenuSelect.js deleted file mode 100644 index 7b1487b50d..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/MenuSelect.js +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import MenuSelect from '../MenuSelect'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('MenuSelect', () => { - it('default menu select', () => { - const tree = renderer - .create( - {}} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default menu select with custom className', () => { - const tree = renderer - .create( - {}} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default menu select with custom id', () => { - const id = 'menu-select'; - const wrapper = mount( - {}} items={[]} canRefine={false} /> - ); - - const select = wrapper.find('select').getDOMNode(); - expect(select.getAttribute('id')).toEqual(id); - }); - - it('default menu select with no refinement', () => { - const tree = renderer - .create( {}} items={[]} canRefine={false} />) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - {}} - items={[ - { label: 'white', value: 'white', count: 10, isRefined: false }, - { label: 'black', value: 'black', count: 20, isRefined: false }, - { label: 'blue', value: 'blue', count: 30, isRefined: false }, - { label: 'green', value: 'green', count: 30, isRefined: false }, - { label: 'red', value: 'red', count: 30, isRefined: false }, - ]} - translations={{ - seeAllOption: 'Everything', - }} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - const items = wrapper.find('option'); - expect(items).toHaveLength(4); // +1 from "see all option" - - wrapper.find('select').simulate('change', { target: { value: 'blue' } }); - - expect(refine).toHaveBeenCalledTimes(1); - expect(refine).toHaveBeenCalledWith('blue'); - - wrapper.unmount(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/NumericMenu.js b/packages/react-instantsearch-dom/src/components/__tests__/NumericMenu.js deleted file mode 100644 index 28c7385f32..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/NumericMenu.js +++ /dev/null @@ -1,268 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import NumericMenu from '../NumericMenu'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('NumericMenu', () => { - it('supports passing items values', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - items={[ - { - label: 'label1', - value: '10:', - isRefined: false, - noRefinement: false, - }, - { - label: 'label2', - value: '10:20', - isRefined: false, - noRefinement: false, - }, - { - label: 'label3', - value: '20:30', - isRefined: false, - noRefinement: false, - }, - { - label: 'label4', - value: '30:', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('supports passing custom className', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - items={[ - { - label: 'label1', - value: '10:', - isRefined: false, - noRefinement: false, - }, - { - label: 'label2', - value: '10:20', - isRefined: false, - noRefinement: false, - }, - { - label: 'label3', - value: '20:30', - isRefined: false, - noRefinement: false, - }, - { - label: 'label4', - value: '30:', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('supports having a selected item', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - items={[ - { - label: 'label1', - value: '10:', - isRefined: false, - noRefinement: false, - }, - { - label: 'label2', - value: '10:20', - isRefined: true, - noRefinement: false, - }, - { - label: 'label3', - value: '20:30', - isRefined: false, - noRefinement: false, - }, - { - label: 'label4', - value: '30:', - isRefined: false, - noRefinement: false, - }, - { label: 'All', value: '', isRefined: false, noRefinement: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('no refinements', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - items={[ - { - label: 'label1', - value: '10:', - isRefined: false, - noRefinement: true, - }, - { - label: 'label2', - value: '10:20', - isRefined: false, - noRefinement: true, - }, - { - label: 'label3', - value: '20:30', - isRefined: false, - noRefinement: true, - }, - { - label: 'label4', - value: '30:', - isRefined: false, - noRefinement: true, - }, - { label: 'All', value: '', isRefined: true, noRefinement: false }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(4); - - const firstItem = items.first().find('input'); - - firstItem.simulate('change', { target: { checked: true } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('10:'); - - wrapper.unmount(); - }); - - it('indicate when there is no refinement', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - const itemWrapper = wrapper.find('.ais-NumericMenu-list--noRefinement'); - expect(itemWrapper).toHaveLength(1); - - const items = wrapper.find('.ais-NumericMenu-item--noRefinement'); - expect(items).toHaveLength(4); - - wrapper.unmount(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Pagination.js b/packages/react-instantsearch-dom/src/components/__tests__/Pagination.js deleted file mode 100644 index a1405ae8eb..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Pagination.js +++ /dev/null @@ -1,395 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Link from '../Link'; -import Pagination from '../Pagination'; - -Enzyme.configure({ adapter: new Adapter() }); - -const REQ_PROPS = { - createURL: () => '#', - refine: () => null, - canRefine: true, -}; - -const DEFAULT_PROPS = { - ...REQ_PROPS, - nbPages: 20, - currentRefinement: 9, -}; - -describe('Pagination', () => { - it('applies its default props', () => { - const tree = renderer.create().toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies its default props without refinement', () => { - const tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies its default props with custom className', () => { - const tree = renderer - .create() - .toJSON(); - - expect(tree).toMatchSnapshot(); - }); - - it('displays the correct padding of links', () => { - let tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('allows toggling display of the first page button on and off', () => { - let tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('indicates when first button is relevant', () => { - let tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('allows toggling display of the last page button on and off', () => { - let tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('allows toggling display of the previous page button on and off', () => { - let tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('allows toggling display of the next page button on and off', () => { - let tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create() - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('lets you force a maximum of pages', () => { - let tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - - tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('lets you customize its theme', () => { - const tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('lets you customize its translations', () => { - const tree = renderer - .create( - `PAGE_${(page + 1).toString()}`, - ariaPrevious: 'ARIA_PREVIOUS', - ariaNext: 'ARIA_NEXT', - ariaFirst: 'ARIA_FIRST', - ariaLast: 'ARIA_LAST', - ariaPage: (page) => `ARIA_PAGE_${(page + 1).toString()}`, - }} - showLast - padding={4} - nbPages={10} - currentRefinement={8} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('disabled all button if no results', () => { - const tree = renderer - .create( - - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value when clicking on a page link', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - wrapper - .find(Link) - .filterWhere((e) => e.text() === '8') - .simulate('click'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual(8); - wrapper - .find(Link) - .filterWhere((e) => e.text() === '9') - .simulate('click'); - expect(refine.mock.calls).toHaveLength(2); - const parameters = refine.mock.calls[1][0]; - expect(parameters.valueOf()).toBe(9); - wrapper - .find('.ais-Pagination-item--previousPage') - .find(Link) - .simulate('click'); - expect(refine.mock.calls).toHaveLength(3); - expect(refine.mock.calls[2][0]).toEqual(8); - wrapper.find('.ais-Pagination-item--nextPage').find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(4); - expect(refine.mock.calls[3][0]).toEqual(10); - wrapper - .find('.ais-Pagination-item--firstPage') - .find(Link) - .simulate('click'); - expect(refine.mock.calls).toHaveLength(5); - expect(refine.mock.calls[4][0]).toEqual(1); - wrapper.find('.ais-Pagination-item--lastPage').find(Link).simulate('click'); - expect(refine.mock.calls).toHaveLength(6); - expect(refine.mock.calls[5][0]).toEqual(20); - }); - - it('ignores special clicks', () => { - const refine = jest.fn(); - const wrapper = mount(); - const el = wrapper.find(Link).filterWhere((e) => e.text() === '8'); - el.simulate('click', { button: 1 }); - el.simulate('click', { altKey: true }); - el.simulate('click', { ctrlKey: true }); - el.simulate('click', { metaKey: true }); - el.simulate('click', { shiftKey: true }); - expect(refine.mock.calls).toHaveLength(0); - }); - - describe('padding behaviour', () => { - it('should be adjusted when currentPage < padding (at the very beginning)', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - const pages = wrapper.find('.ais-Pagination-item--page'); - const pageSelected = wrapper.find('.ais-Pagination-item--selected'); - // Since padding = 2, the Pagination widget's size should be 5 - expect(pages).toHaveLength(5); - - expect(pages.first().text()).toEqual('1'); - - expect(pageSelected.first().text()).toEqual('2'); - expect(pages.at(1).text()).toEqual('2'); - - expect(pages.at(2).text()).toEqual('3'); - expect(pages.at(3).text()).toEqual('4'); - expect(pages.at(4).text()).toEqual('5'); - }); - it('should be adjusted when currentPage < totalPages - padding (at the end)', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - const pages = wrapper.find('.ais-Pagination-item--page'); - const pageSelected = wrapper.find('.ais-Pagination-item--selected'); - // Since padding = 2, the Pagination widget's size should be 5 - expect(pages).toHaveLength(5); - - expect(pages.first().text()).toEqual('14'); - expect(pages.at(1).text()).toEqual('15'); - expect(pages.at(2).text()).toEqual('16'); - expect(pages.at(3).text()).toEqual('17'); - - expect(pageSelected.first().text()).toEqual('18'); - expect(pages.at(4).text()).toEqual('18'); - }); - it('should render the correct padding in every other case', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - const pages = wrapper.find('.ais-Pagination-item--page'); - const pageSelected = wrapper.find('.ais-Pagination-item--selected'); - // Since padding = 2, the Pagination widget's size should be 5 - expect(pages).toHaveLength(5); - - expect(pages.first().text()).toEqual('6'); - expect(pages.at(1).text()).toEqual('7'); - - expect(pageSelected.first().text()).toEqual('8'); - expect(pages.at(2).text()).toEqual('8'); - - expect(pages.at(3).text()).toEqual('9'); - expect(pages.at(4).text()).toEqual('10'); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Panel.js b/packages/react-instantsearch-dom/src/components/__tests__/Panel.js deleted file mode 100644 index 28d9bcb920..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Panel.js +++ /dev/null @@ -1,118 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import { createSerializer } from 'enzyme-to-json'; -import React from 'react'; - -import Panel, { PanelConsumer } from '../Panel'; - -expect.addSnapshotSerializer(createSerializer()); -Enzyme.configure({ adapter: new Adapter() }); - -describe('Panel', () => { - it('expect to render', () => { - const wrapper = shallow( - -
    Hello content
    -
    - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with custom className', () => { - const props = { - className: 'ais-Panel-Breadcrumb', - }; - - const wrapper = shallow( - -
    Hello content
    -
    - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render without refinement', () => { - const wrapper = shallow( - -
    Hello content
    -
    - ); - - wrapper.setState({ canRefine: false }); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with header', () => { - const props = { - header:

    Header

    , - }; - - const wrapper = shallow( - -
    Hello content
    -
    - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with footer', () => { - const props = { - footer:

    Footer

    , - }; - - const wrapper = shallow( - -
    Hello content
    -
    - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to expose context to its children', () => { - let provided; - const wrapper = mount( - - - {(setCanRefine) => { - provided = setCanRefine; - return null; - }} - - - ); - - expect(provided).toEqual(wrapper.instance().setCanRefine); - }); - - it('expect to render when setCanRefine is called', () => { - const wrapper = mount( - - - {(setCanRefine) => ( - - )} - - - ); - - expect(wrapper.state('canRefine')).toBe(true); - expect(wrapper).toMatchSnapshot(); - - // Simulate context call - wrapper.find('button').simulate('click'); - - expect(wrapper.state('canRefine')).toBe(false); - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/PanelCallbackHandler.js b/packages/react-instantsearch-dom/src/components/__tests__/PanelCallbackHandler.js deleted file mode 100644 index 9170744d4b..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/PanelCallbackHandler.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import { createSerializer } from 'enzyme-to-json'; -import React from 'react'; - -import { PanelProvider } from '../Panel'; -import PanelCallbackHandler from '../PanelCallbackHandler'; - -expect.addSnapshotSerializer(createSerializer()); -Enzyme.configure({ adapter: new Adapter() }); - -describe('PanelCallbackHandler', () => { - it('expect to render', () => { - const wrapper = mount( - -
    Hello content
    -
    - ); - - expect(wrapper).toMatchInlineSnapshot(` - - -
    - Hello content -
    -
    -
    - `); - }); - - describe('didMount', () => { - it('expect to call setCanRefine when the context is given', () => { - const setCanRefine = jest.fn(); - - mount( - - -
    Hello content
    -
    -
    - ); - - expect(setCanRefine).toHaveBeenCalledTimes(1); - expect(setCanRefine).toHaveBeenCalledWith(true); - }); - - it('expect to not throw when the context is not given', () => { - expect(() => - shallow( - -
    Hello content
    -
    - ) - ).not.toThrow(); - }); - }); - - describe('didUpdate', () => { - it('expect to call setCanRefine when the context is given', () => { - const setCanRefine = jest.fn(); - - const wrapper = mount( - - -
    Hello content
    -
    -
    - ); - - wrapper.setProps({ - children: ( - -
    Hello content
    -
    - ), - }); - - expect(setCanRefine).toHaveBeenCalledTimes(2); - expect(setCanRefine).toHaveBeenLastCalledWith(false); - }); - - it('expect to not call setCanRefine when the nextProps is the same', () => { - const setCanRefine = jest.fn(); - - const wrapper = mount( - - -
    Hello content
    -
    -
    - ); - - wrapper.setProps({ - children: ( - -
    Hello content
    -
    - ), - }); - - expect(setCanRefine).toHaveBeenCalledTimes(1); - }); - - it('expect to not throw when the context is not given', () => { - expect(() => { - const wrapper = shallow( - -
    Hello content
    -
    - ); - - wrapper.setProps({ canRefine: false }); - }).not.toThrow(); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/PoweredBy.js b/packages/react-instantsearch-dom/src/components/__tests__/PoweredBy.js deleted file mode 100644 index 2c26f2b98e..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/PoweredBy.js +++ /dev/null @@ -1,42 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import PoweredBy from '../PoweredBy'; - -describe('PoweredBy', () => { - it('default', () => { - const tree = renderer - .create( '#'} url="url" />) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default with className', () => { - const tree = renderer - .create( - '#'} - url="url" - /> - ) - .toJSON(); - - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - '#'} - url="url" - translations={{ - searchBy: ' Search By', - }} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/QueryRuleCustomData.tsx b/packages/react-instantsearch-dom/src/components/__tests__/QueryRuleCustomData.tsx deleted file mode 100644 index a73f05aed0..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/QueryRuleCustomData.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import QueryRuleCustomData from '../QueryRuleCustomData'; - -import type { QueryRuleCustomDataProps } from '../QueryRuleCustomData'; - -Enzyme.configure({ adapter: new Adapter() }); - -type CustomDataItem = { - [key: string]: any; -}; - -type CustomDataProps = QueryRuleCustomDataProps; - -describe('QueryRuleCustomData', () => { - it('expects to render the empty container with empty items', () => { - const props: CustomDataProps = { - items: [], - children: jest.fn(({ items }) => - items.map((item) => ( -
    - {item.title} -
    - )) - ), - }; - - const wrapper = shallow(); - - expect(props.children).toHaveBeenCalledTimes(1); - expect(props.children).toHaveBeenCalledWith({ items: props.items }); - expect(wrapper).toMatchSnapshot(); - }); - - it('expects to render multiple items', () => { - const props: CustomDataProps = { - items: [ - { title: 'Image 1', banner: 'image-1.png' }, - { title: 'Image 2', banner: 'image-2.png' }, - ], - children: jest.fn(({ items }) => - items.map((item) => ( -
    - {item.title} -
    - )) - ), - }; - - const wrapper = shallow(); - - expect(props.children).toHaveBeenCalledTimes(1); - expect(props.children).toHaveBeenCalledWith({ items: props.items }); - expect(wrapper).toMatchSnapshot(); - }); - - it('expects to render with custom className', () => { - const props: CustomDataProps = { - items: [], - className: 'CustomClassName', - children: jest.fn(() => null), - }; - - const wrapper = shallow(); - - expect(wrapper.props().className).toContain('CustomClassName'); - expect(wrapper).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/RangeInput.js b/packages/react-instantsearch-dom/src/components/__tests__/RangeInput.js deleted file mode 100644 index 47506f898f..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/RangeInput.js +++ /dev/null @@ -1,320 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import RangeInput, { RawRangeInput } from '../RangeInput'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('RangeInput', () => { - const shallowRender = (props = {}) => { - const defaultProps = { - currentRefinement: { - min: undefined, - max: undefined, - }, - canRefine: true, - precision: 0, - refine: () => {}, - min: undefined, - max: undefined, - }; - - return shallow(); - }; - - it('render with translations', () => { - const props = { - translations: { - submit: 'SUBMIT', - separator: 'SEPARATOR', - }, - }; - - const component = shallowRender(props).shallow(); - - expect(component).toMatchSnapshot(); - }); -}); - -describe('RawRangeInput', () => { - const shallowRender = (props = {}) => { - const defaultProps = { - currentRefinement: { - min: undefined, - max: undefined, - }, - canRefine: true, - precision: 0, - refine: () => {}, - translate: (x) => x, - min: undefined, - max: undefined, - }; - - return shallow(); - }; - - it('render with empty values', () => { - const props = {}; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with empty values when refinement is equal to min / max', () => { - const props = { - currentRefinement: { - min: 0, - max: 500, - }, - min: 0, - max: 500, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with refinement', () => { - const props = { - currentRefinement: { - min: 10, - max: 490, - }, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with min / max', () => { - const props = { - min: 0, - max: 500, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with min only', () => { - const props = { - min: 0, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with max only', () => { - const props = { - max: 500, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with precision of 1', () => { - const props = { - precision: 1, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with precision of 2', () => { - const props = { - precision: 2, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it("render when can't refine", () => { - const props = { - canRefine: false, - min: 0, - max: 100, - currentRefinement: { - min: 10, - max: 90, - }, - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - it('render with custom className', () => { - const props = { - className: 'MyCustomRangeInput', - }; - - const component = shallowRender(props); - - expect(component).toMatchSnapshot(); - }); - - describe('didUpdate', () => { - it('expect to update state when props have changed', () => { - const props = { - canRefine: false, - currentRefinement: { - min: 0, - max: 100, - }, - }; - - const wrapper = shallowRender(props); - - wrapper.setProps({ - canRefine: true, - currentRefinement: { - min: 10, - max: 90, - }, - }); - - wrapper.update(); - - expect(wrapper.state()).toEqual({ - from: 10, - to: 90, - }); - }); - - it("expect to not update state when props don't have changed", () => { - const props = { - canRefine: true, - currentRefinement: { - min: 0, - max: 100, - }, - }; - - const wrapper = shallowRender(props); - - wrapper.setState({ - from: 10, - to: 90, - }); - - wrapper.setProps({ - canRefine: true, - currentRefinement: { - min: 0, - max: 100, - }, - }); - - wrapper.update(); - - expect(wrapper.state()).toEqual({ - from: 10, - to: 90, - }); - }); - }); - - describe('onChange', () => { - it('expect to update min onChange', () => { - const props = {}; - const component = shallowRender(props); - - component - .find('input') - .first() - .simulate('change', { - currentTarget: { - value: 10, - }, - }); - - expect(component).toMatchSnapshot(); - expect(component.state()).toEqual({ - from: 10, - to: '', - }); - }); - - it('expect to update max onChange', () => { - const props = {}; - const component = shallowRender(props); - - component - .find('input') - .last() - .simulate('change', { - currentTarget: { - value: 490, - }, - }); - - expect(component).toMatchSnapshot(); - expect(component.state()).toEqual({ - from: '', - to: 490, - }); - }); - }); - - describe('onSubmit', () => { - it('expect to call refine onSubmit with values', () => { - const props = { - refine: jest.fn(), - }; - - const event = { - preventDefault: jest.fn(), - }; - - const component = shallowRender(props); - - component.setState({ - from: 10, - to: 490, - }); - - component.find('form').simulate('submit', event); - - expect(event.preventDefault).toHaveBeenCalled(); - expect(props.refine).toHaveBeenCalledWith({ - min: 10, - max: 490, - }); - }); - - it('expect to not call refine with empty string', () => { - const props = { - refine: jest.fn(), - }; - - const event = { - preventDefault: jest.fn(), - }; - - const component = shallowRender(props); - - component.find('form').simulate('submit', event); - - expect(event.preventDefault).toHaveBeenCalled(); - expect(props.refine).toHaveBeenCalledWith({ - min: '', - max: '', - }); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/RatingMenu.js b/packages/react-instantsearch-dom/src/components/__tests__/RatingMenu.js deleted file mode 100644 index b31efe8b2e..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/RatingMenu.js +++ /dev/null @@ -1,319 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import RatingMenu from '../RatingMenu'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('RatingMenu', () => { - it('supports passing max/min values', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - min={1} - max={5} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('supports passing max/min values smaller than count max & min', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - min={2} - max={4} - currentRefinement={{}} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('supports passing custom className', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - min={1} - max={5} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('expect to render without refinement', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - min={1} - max={5} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={false} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - translations={{ - ratingLabel: ' & Up', - }} - min={1} - max={5} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('expect to not throw when only min is defined', () => { - expect(() => { - renderer.create( - '#'} - refine={() => null} - translations={{ - ratingLabel: ' & Up', - }} - min={3} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ); - }).not.toThrow(); - }); - - it('expect to render when only max is defined', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - translations={{ - ratingLabel: ' & Up', - }} - max={3} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('expect to render from from 1 when min is negative', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - translations={{ - ratingLabel: ' & Up', - }} - min={-5} - max={5} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('expect to render nothing when min is higher than max', () => { - const tree = renderer - .create( - '#'} - refine={() => null} - translations={{ - ratingLabel: ' & Up', - }} - min={5} - max={3} - currentRefinement={{ min: 1, max: 5 }} - count={[ - { value: '1', count: 1 }, - { value: '2', count: 2 }, - { value: '3', count: 3 }, - { value: '4', count: 4 }, - { value: '5', count: 5 }, - ]} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - const refine = jest.fn(); - const createURL = jest.fn(); - const ratingMenu = ( - - ); - - beforeEach(() => { - refine.mockClear(); - createURL.mockClear(); - }); - - it('should create an URL for each row except for the largest: the default selected one', () => { - const wrapper = mount(ratingMenu); - - expect(createURL.mock.calls).toHaveLength(3); - expect(createURL.mock.calls[0][0]).toEqual({ min: 4, max: 5 }); - expect(createURL.mock.calls[1][0]).toEqual({ min: 3, max: 5 }); - expect(createURL.mock.calls[2][0]).toEqual({ min: 2, max: 5 }); - - wrapper.unmount(); - }); - - it('refines its value on change', () => { - const wrapper = mount(ratingMenu); - const links = wrapper.find('.ais-RatingMenu-link'); - expect(links).toHaveLength(5); - - let selectedItem = wrapper.find('.ais-RatingMenu-item--selected'); - expect(selectedItem).toHaveLength(1); - - links.first().simulate('click'); - - expect(refine.mock.calls).toHaveLength(0); - - selectedItem = wrapper.find('.ais-RatingMenu-item--selected'); - expect(selectedItem).toBeDefined(); - - const disabledIcon = wrapper - .find('.ais-RatingMenu-item--disabled') - .find('.ais-RatingMenu-starIcon'); - - expect(disabledIcon).toHaveLength(5); - wrapper.unmount(); - }); - - it('should display the right number of stars', () => { - const wrapper = mount(ratingMenu); - wrapper.find('.ais-RatingMenu-link').last().simulate('click'); - - const selectedItem = wrapper.find('.ais-RatingMenu-item--selected'); - - const fullIcon = selectedItem.find('.ais-RatingMenu-starIcon--full'); - const emptyIcon = selectedItem.find('.ais-RatingMenu-starIcon--empty'); - - expect(fullIcon).toHaveLength(1); - expect(emptyIcon).toHaveLength(4); - wrapper.unmount(); - }); - - it('clicking on the selected refinement should select the largest range', () => { - const wrapper = mount(ratingMenu); - wrapper.setProps({ currentRefinement: { min: 4, max: 5 } }); - - const links = wrapper.find('.ais-RatingMenu-link'); - links.at(1).simulate('click'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual({ min: 1, max: 5 }); - wrapper.unmount(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/RefinementList.js b/packages/react-instantsearch-dom/src/components/__tests__/RefinementList.js deleted file mode 100644 index 449dca96c2..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/RefinementList.js +++ /dev/null @@ -1,368 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import RefinementList from '../RefinementList'; - -Enzyme.configure({ adapter: new Adapter() }); - -jest.mock('../../widgets/Highlight', () => () => null); - -describe('RefinementList', () => { - it('default refinement list', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - searchForItems={() => null} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: true }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default refinement list with custom className', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - searchForItems={() => null} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: true }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('default refinement list with no refinement', () => { - const tree = renderer - .create( - null} - createURL={() => '#'} - searchForItems={() => null} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: true }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={false} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refinement list with search inside items but no search results', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - searchable - createURL={() => '#'} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: true }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - isFromSearch={false} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refinement list with search inside items with search results', () => { - const tree = renderer - .create( - null} - searchable - searchForItems={() => null} - createURL={() => '#'} - items={[ - { - label: 'white', - value: ['white'], - count: 10, - isRefined: true, - _highlightResult: { label: 'white' }, - }, - ]} - isFromSearch={true} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('applies translations', () => { - const tree = renderer - .create( - null} - searchForItems={() => null} - searchable - createURL={() => '#'} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: false }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - isFromSearch={false} - translations={{ - showMore: ' display more', - noResults: ' no results', - placeholder: 'placeholder', - }} - canRefine={true} - /> - ) - .toJSON(); - expect(tree).toMatchSnapshot(); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - null} - createURL={() => '#'} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: false }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - ]} - isFromSearch={false} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(3); - - const firstItem = items.first().find('input[type="checkbox"]'); - - firstItem.simulate('change', { target: { checked: true } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual(['white']); - - wrapper.unmount(); - }); - - it('should respect defined limits', () => { - const refine = jest.fn(); - const wrapper = mount( - null} - createURL={() => '#'} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: false }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - { label: 'blue', value: ['blue'], count: 30, isRefined: false }, - { label: 'red', value: ['red'], count: 30, isRefined: false }, - { label: 'green', value: ['green'], count: 30, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - wrapper.find('button').simulate('click'); - - expect(wrapper.find('li')).toHaveLength(4); - - wrapper.unmount(); - }); - - it('should disabled show more when no more item to display', () => { - const refine = jest.fn(); - const wrapper = mount( - null} - createURL={() => '#'} - items={[ - { label: 'white', value: ['white'], count: 10, isRefined: false }, - { label: 'black', value: ['black'], count: 20, isRefined: false }, - ]} - limit={2} - showMoreLimit={4} - showMore={true} - isFromSearch={false} - canRefine={true} - /> - ); - - const items = wrapper.find('li'); - - expect(items).toHaveLength(2); - - expect(wrapper.find('button[disabled]')).toBeDefined(); - - wrapper.unmount(); - }); - - describe('search inside items', () => { - const refine = jest.fn(); - const searchForItems = jest.fn(); - const refinementList = ( - '#'} - items={[ - { - label: 'white', - value: ['white'], - count: 10, - isRefined: false, - _highlightResult: { label: { value: 'white' } }, - }, - { - label: 'black', - value: ['black'], - count: 20, - isRefined: false, - _highlightResult: { label: { value: 'black' } }, - }, - ]} - isFromSearch={true} - canRefine={true} - /> - ); - - it('a searchbox should be displayed if the feature is activated', () => { - const wrapper = mount(refinementList); - - const searchBox = wrapper.find('input[type="search"]'); - - expect(searchBox).toBeDefined(); - - wrapper.unmount(); - }); - - it('searching for a value should call searchForItems', () => { - const wrapper = mount(refinementList); - - wrapper - .find('input[type="search"]') - .simulate('change', { target: { value: 'query' } }); - - expect(searchForItems.mock.calls).toHaveLength(1); - expect(searchForItems.mock.calls[0][0]).toBe('query'); - - wrapper.unmount(); - }); - - it('should refine the selected value and display selected refinement back', () => { - const wrapper = mount(refinementList); - - const firstItem = wrapper - .find('li') - .first() - .find('input[type="checkbox"]'); - firstItem.simulate('change', { target: { checked: true } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual(['white']); - expect(wrapper.find('input[type="search"]').props().value).toBe(''); - - const selectedRefinements = wrapper.find('li'); - expect(selectedRefinements).toHaveLength(2); - - wrapper.unmount(); - }); - - it('hit enter on the search values results list should refine the first facet value', () => { - refine.mockClear(); - const wrapper = mount(refinementList); - - wrapper.find('form').simulate('submit'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual(['white']); - expect(wrapper.find('input[type="search"]').props().value).toBe(''); - - const selectedRefinements = wrapper.find('li'); - expect(selectedRefinements).toHaveLength(2); - - wrapper.unmount(); - }); - - it('hit enter on an empty search values results list should do nothing', () => { - const emptyRefinementList = ( - '#'} - items={[]} - isFromSearch={true} - canRefine={true} - /> - ); - - refine.mockClear(); - const wrapper = mount(emptyRefinementList); - const input = wrapper.find('input[type="search"]'); - input.props().value = 'white'; - - wrapper.find('form').simulate('submit'); - - expect(refine.mock.calls).toHaveLength(0); - expect(input.props().value).toBe('white'); - - const selectedRefinements = wrapper.find('li'); - expect(selectedRefinements).toHaveLength(0); - - wrapper.unmount(); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/RelevantSort.tsx b/packages/react-instantsearch-dom/src/components/__tests__/RelevantSort.tsx deleted file mode 100644 index 68d107e0cf..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/RelevantSort.tsx +++ /dev/null @@ -1,194 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import RelevantSort from '../RelevantSort'; - -import type { RelevantSortComponentProps } from '../RelevantSort'; - -describe('RelevantSort', () => { - it("returns null if it's not a virtual replica", () => { - const tree = renderer.create( - {}} - /> - ); - - expect(tree.toJSON()).toBeNull(); - }); - - it('accepts a custom className', () => { - const tree = renderer.create( - {}} - /> - ); - - expect(tree.root.props.className.includes('MyCustomRelevantSort')).toBe( - true - ); - }); - - it('forward isRelevantSorted to props components', () => { - const mockTextComponent = jest.fn(() => null); - - const mockButtonTextComponent = jest.fn(() => null); - - renderer.create( - {}} - textComponent={mockButtonTextComponent} - /> - ); - - expect(mockTextComponent).toHaveBeenCalledWith( - { - isRelevantSorted: true, - }, - {} - ); - expect(mockButtonTextComponent).toHaveBeenCalledWith( - { - isRelevantSorted: true, - }, - {} - ); - }); - - it('renders with the default ButtonTextComponent', () => { - const tree = renderer.create( - {}} - /> - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    -
    - -
    - `); - }); - - it('renders with a custom ButtonTextComponent', () => { - const tree = renderer.create( - ( - - {isRelevantSorted ? 'See all results' : 'See relevant results'} - - )} - isVirtualReplica={true} - isRelevantSorted={true} - refine={() => {}} - /> - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    -
    - -
    - `); - }); - - it('renders without a textComponent', () => { - const tree = renderer.create( - {}} - /> - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    -
    - -
    - `); - }); - - it('renders with a custom textComponent', () => { - const tree = renderer.create( - {}} - textComponent={({ isRelevantSorted }: RelevantSortComponentProps) => ( -

    - {isRelevantSorted - ? 'We removed some search results to show you the most relevant ones' - : 'Currently showing all results'} -

    - )} - /> - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    -
    -

    - Currently showing all results -

    -
    - -
    - `); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/ScrollTo.js b/packages/react-instantsearch-dom/src/components/__tests__/ScrollTo.js deleted file mode 100644 index efcb617f76..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/ScrollTo.js +++ /dev/null @@ -1,70 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import ScrollTo from '../ScrollTo'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('ScrollTo', () => { - it('expect to render', () => { - const wrapper = shallow( - - content - - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to call scrollIntoView', () => { - const wrapper = shallow( - - content - - ); - - // Simulate ref - wrapper.instance().el = { - scrollIntoView: jest.fn(), - }; - - wrapper.setProps({ value: 5 }); - - expect(wrapper.instance().el.scrollIntoView).toHaveBeenCalled(); - }); - - it('expect to not call scrollIntoView when previous value do not have changed', () => { - const wrapper = shallow( - - content - - ); - - // Simulate ref - wrapper.instance().el = { - scrollIntoView: jest.fn(), - }; - - wrapper.setProps({ value: 4 }); - - expect(wrapper.instance().el.scrollIntoView).not.toHaveBeenCalled(); - }); - - it('expect to not call scrollIntoView when hasNotChanged is false', () => { - const wrapper = shallow( - - content - - ); - - // Simulate ref - wrapper.instance().el = { - scrollIntoView: jest.fn(), - }; - - wrapper.setProps({ value: 5 }); - - expect(wrapper.instance().el.scrollIntoView).not.toHaveBeenCalled(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/SearchBox.js b/packages/react-instantsearch-dom/src/components/__tests__/SearchBox.js deleted file mode 100644 index 4619f01611..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/SearchBox.js +++ /dev/null @@ -1,367 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; -import renderer from 'react-test-renderer'; - -import SearchBox from '../SearchBox'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('SearchBox', () => { - it('applies its default props', () => { - const instance = renderer.create( null} />); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('applies its default props with custom className', () => { - const instance = renderer.create( - null} /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('applies its default props with custom inputId', () => { - const inputId = 'search-box'; - const wrapper = mount( null} />); - - const input = wrapper.find('input').getDOMNode(); - expect(input.getAttribute('id')).toEqual(inputId); - }); - - it('transfers the autoFocus prop to the underlying input element', () => { - const instance = renderer.create( - null} autoFocus /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('treats its query prop as its input value', () => { - const instance = renderer.create( - null} currentRefinement="QUERY1" /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.update( - null} currentRefinement="QUERY2" /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('lets you customize its theme', () => { - const instance = renderer.create( - null} - theme={{ - root: 'ROOT', - wrapper: 'WRAPPER', - input: 'INPUT', - submit: 'SUBMIT', - reset: 'RESET', - }} - /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('lets you give custom components for reset and submit', () => { - const instance = renderer.create( - null} - submit={🔍} - reset={ - - - - } - /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('lets you customize its translations', () => { - const instance = renderer.create( - null} - translations={{ - resetTitle: 'RESET_TITLE', - placeholder: 'PLACEHOLDER', - }} - /> - ); - - expect(instance.toJSON()).toMatchSnapshot(); - - instance.unmount(); - }); - - it('treats query as a default value when searchAsYouType=false', () => { - const wrapper = mount( - null} - currentRefinement="QUERY1" - searchAsYouType={false} - /> - ); - - expect(wrapper.find('input').props().value).toBe('QUERY1'); - - wrapper.find('input').simulate('change', { target: { value: 'QUERY2' } }); - - expect(wrapper.find('input').props().value).toBe('QUERY2'); - - wrapper.unmount(); - }); - - it('refines its value on change when searchAsYouType=true', () => { - const refine = jest.fn(); - const wrapper = mount(); - - wrapper.find('input').simulate('change', { target: { value: 'hello' } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toBe('hello'); - - wrapper.unmount(); - }); - - it('only refines its query on submit when searchAsYouType=false', () => { - const refine = jest.fn(); - const wrapper = mount( - - ); - - wrapper.find('input').simulate('change', { target: { value: 'hello' } }); - - expect(refine.mock.calls).toHaveLength(0); - - wrapper.find('form').simulate('submit'); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toBe('hello'); - - wrapper.unmount(); - }); - - it('onSubmit behavior should be override if provided as props', () => { - const onSubmit = jest.fn(); - const refine = jest.fn(); - const wrapper = mount( - - ); - - wrapper.find('form').simulate('submit'); - - expect(onSubmit.mock.calls).toHaveLength(1); - expect(refine.mock.calls).toHaveLength(0); - - wrapper.unmount(); - }); - - it('focuses the input when one of the keys in focusShortcuts is pressed', () => { - let input; - - const wrapper = mount( - null} - focusShortcuts={['s', 84]} - inputRef={(node) => { - input = node; - }} - /> - ); - - input.focus = jest.fn(); - - const event1 = new KeyboardEvent('keydown', { keyCode: 82 }); - document.dispatchEvent(event1); - expect(input.focus.mock.calls).toHaveLength(0); - - const event2 = new KeyboardEvent('keydown', { keyCode: 83 }); - document.dispatchEvent(event2); - expect(input.focus.mock.calls).toHaveLength(1); - - const event3 = new KeyboardEvent('keydown', { keyCode: 84 }); - document.dispatchEvent(event3); - expect(input.focus.mock.calls).toHaveLength(2); - - wrapper.unmount(); - }); - - it('should accept `onXXX` events', () => { - const onSubmit = jest.fn(); - const onReset = jest.fn(); - - const inputEventsList = [ - 'onChange', - 'onFocus', - 'onBlur', - 'onSelect', - 'onKeyDown', - 'onKeyPress', - ]; - - const inputProps = inputEventsList.reduce( - (props, prop) => ({ ...props, [prop]: jest.fn() }), - {} - ); - - const wrapper = mount( - null} - onSubmit={onSubmit} - onReset={onReset} - {...inputProps} - /> - ); - - // simulate form events `onReset` && `onSubmit` - wrapper.find('form').simulate('submit'); - expect(onSubmit).toHaveBeenCalled(); - - wrapper.find('form').simulate('reset'); - expect(onReset).toHaveBeenCalled(); - - // simulate input search events - inputEventsList.forEach((eventName) => { - wrapper - .find('input') - .simulate(eventName.replace(/^on/, '').toLowerCase()); - - expect(inputProps[eventName]).toHaveBeenCalled(); - }); - - wrapper.unmount(); - }); - - it('should render the loader if showLoadingIndicator is true', () => { - const instanceWithoutLoadingIndicator = renderer.create( - null} showLoadingIndicator /> - ); - - expect(instanceWithoutLoadingIndicator.toJSON()).toMatchSnapshot(); - - const instanceWithLoadingIndicator = renderer.create( - null} showLoadingIndicator isSearchStalled /> - ); - - expect(instanceWithLoadingIndicator.toJSON()).toMatchSnapshot(); - - instanceWithoutLoadingIndicator.unmount(); - instanceWithLoadingIndicator.unmount(); - }); - - it('expect to clear the query when the form is reset with searchAsYouType=true', () => { - const refine = jest.fn(); - - const wrapper = shallow( - - ).dive(); - - // Simulate the ref - wrapper.instance().input = { focus: jest.fn() }; - - wrapper.find('form').simulate('reset'); - - expect(refine).toHaveBeenCalledWith(''); - expect(wrapper.instance().input.focus).toHaveBeenCalled(); - }); - - it('expect to clear the query when the form is reset with searchAsYouType=false', () => { - const refine = jest.fn(); - - const wrapper = shallow( - - ).dive(); - - // Simulate the ref - wrapper.instance().input = { focus: jest.fn() }; - - // Simulate change event - wrapper.setState({ query: 'Hello' }); - - wrapper.find('form').simulate('reset'); - - expect(refine).toHaveBeenCalledWith(''); - expect(wrapper.instance().input.focus).toHaveBeenCalled(); - expect(wrapper.state()).toEqual({ query: '' }); - }); - - it('should point created refs to its input element', () => { - const inputRef = React.createRef(); - const wrapper = mount( - null} inputRef={inputRef} /> - ); - - const refSpy = jest.spyOn(inputRef.current, 'focus'); - - // Trigger input.focus() - wrapper.find('form').simulate('reset'); - - expect(refSpy).toHaveBeenCalled(); - expect(inputRef.current.tagName).toEqual('INPUT'); - }); - - it('should return a ref when given a callback as input ref', () => { - let inputRef; - const wrapper = mount( - null} - inputRef={(ref) => { - inputRef = ref; - }} - /> - ); - - const refSpy = jest.spyOn(inputRef, 'focus'); - - // Trigger input.focus() - wrapper.find('form').simulate('reset'); - - expect(refSpy).toHaveBeenCalled(); - expect(inputRef.tagName).toEqual('INPUT'); - }); - - it('should point created refs to its form element', () => { - const formRef = React.createRef(); - mount( null} formRef={formRef} />); - - expect(formRef.current.tagName).toEqual('FORM'); - }); - - it('should return a ref when given a callback as form ref', () => { - let formRef; - mount( - null} - formRef={(ref) => { - formRef = ref; - }} - /> - ); - - expect(formRef.tagName).toEqual('FORM'); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Snippet.js b/packages/react-instantsearch-dom/src/components/__tests__/Snippet.js deleted file mode 100644 index ea6f121cd6..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Snippet.js +++ /dev/null @@ -1,122 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Snippet from '../Snippet'; - -describe('Snippet', () => { - it('parses an highlighted snippet attribute of hit object', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _snippetResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('renders a hit with a custom tag correctly', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _snippetResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - tagName="strong" - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); - - it('renders a hit with a custom className', () => { - const hitFromAPI = { - objectID: 0, - deep: { attribute: { value: 'awesome highlighted hit!' } }, - _snippetResult: { - deep: { - attribute: { - value: { - value: - 'awesome highlighted hit!', - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: [''], - }, - }, - }, - }, - }; - - const highlight = () => [ - { value: 'awesome ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 'ghlighted ', isHighlighted: false }, - { value: 'hi', isHighlighted: true }, - { value: 't!', isHighlighted: false }, - ]; - - const tree = renderer.create( - x.join(' ')} - className="MyCustomSnippet" - attribute="deep.attribute.value" - hit={hitFromAPI} - highlight={highlight} - /> - ); - expect(tree.toJSON()).toMatchSnapshot(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/SortBy.js b/packages/react-instantsearch-dom/src/components/__tests__/SortBy.js deleted file mode 100644 index a02aceef98..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/SortBy.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow, mount } from 'enzyme'; -import React from 'react'; - -import SortBy from '../SortBy'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('SortBy', () => { - it('expect to render with custom className', () => { - const wrapper = shallow( - '#'} - items={[ - { value: 'index1', label: 'index name 1' }, - { value: 'index2', label: 'index name 2' }, - { value: 'index3', label: 'index name 3' }, - { value: 'index4', label: 'index name 4' }, - ]} - currentRefinement={'index1'} - refine={() => null} - /> - ); - - expect(wrapper).toMatchSnapshot(); - }); - - it('should forward the id to Select', () => { - const id = 'ais-select'; - const wrapper = mount( - null} - /> - ); - - const select = wrapper.find('select').getDOMNode(); - expect(select.getAttribute('id')).toEqual(id); - }); - - it('refines its value on change', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { value: 'index1', label: 'index name 1' }, - { value: 'index2', label: 'index name 2' }, - { value: 'index3', label: 'index name 3' }, - { value: 'index4', label: 'index name 4' }, - ]} - currentRefinement={'index1'} - refine={refine} - /> - ); - - const selectedValue = wrapper.find('select'); - expect(selectedValue.find('option')).toHaveLength(4); - expect(selectedValue.find('option').first().text()).toBe('index name 1'); - - selectedValue - .find('select') - .simulate('change', { target: { value: 'index3' } }); - - expect(refine.mock.calls).toHaveLength(1); - expect(refine.mock.calls[0][0]).toEqual('index3'); - }); - - it('should use value if no label provided', () => { - const refine = jest.fn(); - const wrapper = mount( - '#'} - items={[ - { value: 'index1' }, - { value: 'index2' }, - { value: 'index3' }, - { value: 'index4' }, - ]} - refine={refine} - currentRefinement={'index1'} - /> - ); - - const selectedValue = wrapper.find('select'); - expect(selectedValue.find('option')).toHaveLength(4); - expect(selectedValue.find('option').first().text()).toBe('index1'); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/Stats.tsx b/packages/react-instantsearch-dom/src/components/__tests__/Stats.tsx deleted file mode 100644 index f1ff1faa42..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/Stats.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import React from 'react'; -import renderer from 'react-test-renderer'; - -import Stats from '../Stats'; - -describe('Stats', () => { - it('renders with default props', () => { - const tree = renderer.create( - - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    - - 42 results found in 0ms - -
    - `); - }); - - it('accepts a custom className', () => { - const tree = renderer.create( - - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    - - 42 results found in 0ms - -
    - `); - }); - - it('renders rely on areHitsSorted', () => { - const tree = renderer.create( - - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    - - 21 relevant results sorted out of 42 found in 0ms - -
    - `); - }); - - it('renders default implementation if nbHits is equal to nbSortedHits', () => { - const tree = renderer.create( - - ); - - expect(tree.toJSON()).toMatchInlineSnapshot(` -
    - - 42 results found in 0ms - -
    - `); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/ToggleRefinement.js b/packages/react-instantsearch-dom/src/components/__tests__/ToggleRefinement.js deleted file mode 100644 index 904074367a..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/ToggleRefinement.js +++ /dev/null @@ -1,78 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { shallow } from 'enzyme'; -import React from 'react'; - -import ToggleRefinement from '../ToggleRefinement'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('ToggleRefinement', () => { - const defaultProps = { - currentRefinement: true, - label: 'toggle the refinement', - canRefine: true, - refine: () => {}, - }; - - it('expect to render with a positive currentRefinement', () => { - const props = { - ...defaultProps, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with a negative currentRefinement', () => { - const props = { - ...defaultProps, - currentRefinement: false, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with a negative canRefine', () => { - const props = { - ...defaultProps, - canRefine: false, - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to render with custom className', () => { - const props = { - ...defaultProps, - className: 'MyCustomToggleRefinement', - }; - - const wrapper = shallow(); - - expect(wrapper).toMatchSnapshot(); - }); - - it('expect to call refine onChange', () => { - const props = { - ...defaultProps, - refine: jest.fn(), - }; - - const wrapper = shallow(); - - expect(props.refine).not.toHaveBeenCalled(); - - wrapper.find('input[type="checkbox"]').simulate('change', { - target: { - checked: false, - }, - }); - - expect(props.refine).toHaveBeenCalledWith(false); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/VoiceSearch.tsx b/packages/react-instantsearch-dom/src/components/__tests__/VoiceSearch.tsx deleted file mode 100644 index c73abfb8e4..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/VoiceSearch.tsx +++ /dev/null @@ -1,125 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import Enzyme, { mount } from 'enzyme'; -import { createSerializer } from 'enzyme-to-json'; -import React from 'react'; - -import VoiceSearch from '../VoiceSearch'; - -import type { InnerComponentProps } from '../VoiceSearch'; - -expect.addSnapshotSerializer(createSerializer() as any); -Enzyme.configure({ adapter: new Adapter() }); - -const mockGetState = jest.fn().mockImplementation(() => ({})); -const mockIsBrowserSupported = jest.fn().mockImplementation(() => true); -const mockIsListening = jest.fn(); -const mockToggleListening = jest.fn(); -const mockDispose = jest.fn(); - -jest.mock('../../lib/voiceSearchHelper', () => { - return () => { - return { - getState: mockGetState, - isBrowserSupported: mockIsBrowserSupported, - isListening: mockIsListening, - toggleListening: mockToggleListening, - dispose: mockDispose, - }; - }; -}); - -describe('VoiceSearch', () => { - afterEach(() => { - mockGetState.mockImplementation(() => ({})); - mockIsBrowserSupported.mockImplementation(() => true); - mockIsListening.mockClear(); - mockToggleListening.mockClear(); - }); - - describe('button', () => { - it('calls toggleListening when button is clicked', () => { - const wrapper = mount(); - wrapper.find('button').simulate('click'); - expect(mockToggleListening).toHaveBeenCalledTimes(1); - }); - }); - - describe('Rendering', () => { - it('with default props', () => { - const wrapper = mount(); - expect(wrapper).toMatchSnapshot(); - }); - - it('with custom component for button with isListening: false', () => { - const customButtonText = ({ isListening }: { isListening: boolean }) => - isListening ? 'Stop' : 'Start'; - - const wrapper = mount( - - ); - expect(wrapper.find('button').text()).toBe('Start'); - }); - - it('with custom component for button with isListening: true', () => { - const customButtonText = ({ isListening }: { isListening: boolean }) => - isListening ? 'Stop' : 'Start'; - mockIsListening.mockImplementation(() => true); - - const wrapper = mount( - - ); - expect(wrapper.find('button').text()).toBe('Stop'); - }); - - it('renders a disabled button when the browser is not supported', () => { - mockIsBrowserSupported.mockImplementation(() => false); - const wrapper = mount(); - expect(wrapper.find('button').prop('title')).toBe( - 'Search by voice (not supported on this browser)' - ); - expect(wrapper.find('button').prop('disabled')).toBe(true); - }); - - it('with custom template for status', () => { - const customStatus = ({ - status, - errorCode, - isListening, - transcript, - isSpeechFinal, - isBrowserSupported, - }: InnerComponentProps) => ( -
    -

    status: {status}

    -

    errorCode: {errorCode}

    -

    isListening: {isListening ? 'true' : 'false'}

    -

    transcript: {transcript}

    -

    isSpeechFinal: {isSpeechFinal ? 'true' : 'false'}

    -

    isBrowserSupported: {isBrowserSupported ? 'true' : 'false'}

    -
    - ); - - mockIsListening.mockImplementation(() => true); - mockGetState.mockImplementation(() => ({ - status: 'recognizing', - transcript: 'Hello', - isSpeechFinal: false, - errorCode: undefined, - })); - - const wrapper = mount(); - expect(wrapper.find('.ais-VoiceSearch-status')).toMatchSnapshot(); - }); - - it('calls voiceSearchHelper.dispose() on unmount', () => { - const wrapper = mount(); - wrapper.find('button').simulate('click'); - wrapper.unmount(); - expect(mockDispose).toHaveBeenCalledTimes(1); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Breadcrumb.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Breadcrumb.js.snap deleted file mode 100644 index f0aebbacda..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Breadcrumb.js.snap +++ /dev/null @@ -1,316 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Breadcrumb has a separator prop that can be a custom component 1`] = ` -
    - -
    -`; - -exports[`Breadcrumb has customizable translations 1`] = ` -
    - -
    -`; - -exports[`Breadcrumb outputs the default breadcrumb 1`] = ` -
    - -
    -`; - -exports[`Breadcrumb outputs the default breadcrumb with a custom className 1`] = ` -
    - -
    -`; - -exports[`Breadcrumb outputs the default breadcrumb with no refinement 1`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ClearRefinements.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ClearRefinements.js.snap deleted file mode 100644 index ddc5e21cec..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ClearRefinements.js.snap +++ /dev/null @@ -1,43 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ClearRefinements has a disabled mode 1`] = ` -
    - -
    -`; - -exports[`ClearRefinements renders a clickable button 1`] = ` -
    - -
    -`; - -exports[`ClearRefinements renders a clickable button with a custom className 1`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/CurrentRefinements.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/CurrentRefinements.js.snap deleted file mode 100644 index 5ac83b0a83..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/CurrentRefinements.js.snap +++ /dev/null @@ -1,240 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`CurrentRefinements - Connected expect to render a list of current refinements 1`] = ` -
    -
      -
    • - - color: Red - - - - -
    • -
    • - - category: - - - - iPhone - - - - - - iPad - - - -
    • -
    -
    -`; - -exports[`CurrentRefinements - Connected expect to render a list of current refinements with custom translations 1`] = ` -
    -
      -
    • - - color: Red - - - - -
    • -
    • - - category: - - - - iPhone - - - - - - iPad - - - -
    • -
    -
    -`; - -exports[`CurrentRefinements expect to render a list of current refinements 1`] = ` -
    -
      -
    • - - color: Red - - - - -
    • -
    • - - category: - - - - iPhone - - - - - - iPad - - - -
    • -
    -
    -`; - -exports[`CurrentRefinements expect to render a list with a custom className 1`] = ` -
    -
      -
    -`; - -exports[`CurrentRefinements expect to render a list without refinements 1`] = ` -
    -
      -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HierarchicalMenu.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HierarchicalMenu.js.snap deleted file mode 100644 index 6bd0ec285b..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HierarchicalMenu.js.snap +++ /dev/null @@ -1,333 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`HierarchicalMenu applies translations 1`] = ` - -`; - -exports[`HierarchicalMenu default hierarchical menu 1`] = ` - -`; - -exports[`HierarchicalMenu default hierarchical menu with a custom className 1`] = ` - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlight.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlight.js.snap deleted file mode 100644 index 5a8d743438..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlight.js.snap +++ /dev/null @@ -1,97 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Highlight parses an highlighted attribute of hit object 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; - -exports[`Highlight renders a hit with a custom className 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; - -exports[`Highlight renders a hit with a custom tag correctly 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlighter.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlighter.js.snap deleted file mode 100644 index 9d7921dafc..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Highlighter.js.snap +++ /dev/null @@ -1,482 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Highlighter - Highlight renders a highlight 1`] = ` - - test - -`; - -exports[`Highlighter - Highlight renders a nonhighlight 1`] = ` -
    - test -
    -`; - -exports[`Highlighter - multi renders a custom className 1`] = ` - - - - - , - - - - - - - , - - - - - - -`; - -exports[`Highlighter - multi renders a highlighted value 1`] = ` - - - - - , - - - - - - - , - - - - - - -`; - -exports[`Highlighter - multi renders a highlighted value with a custom nonHighlightedTagName 1`] = ` - - - - - , - - - - - - - , - - - - - - -`; - -exports[`Highlighter - multi renders a highlighted value with a custom separator 1`] = ` - - - - - - - - - - - - - - - - - - - - -`; - -exports[`Highlighter - multi renders a highlighted value with a custom tagName 1`] = ` - - - - - , - - - - - - - , - - - - - - -`; - -exports[`Highlighter - multi renders a non highlighted value 1`] = ` - - - - - , - - - - - - , - - - - - - -`; - -exports[`Highlighter - simple renders a highlighted value 1`] = ` - - - - -`; - -exports[`Highlighter - simple renders a highlighted value with a custom nonHighlightedTagName 1`] = ` - - - - -`; - -exports[`Highlighter - simple renders a highlighted value with a custom tagName 1`] = ` - - - - -`; - -exports[`Highlighter - simple renders a non highlighted value 1`] = ` - - - -`; - -exports[`Highlighter - simple renders with a custom className 1`] = ` - - - - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Hits.tsx.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Hits.tsx.snap deleted file mode 100644 index 7626f41400..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Hits.tsx.snap +++ /dev/null @@ -1,65 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Hits accepts a custom className 1`] = ` -
    -
      -
    • -
      -
    • -
    • -
      -
    • -
    • -
      -
    • -
    -
    -`; - -exports[`Hits accepts a hitComponent prop 1`] = ` -
    -
      -
    • -
      -
    • -
    • -
      -
    • -
    • -
      -
    • -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HitsPerPage.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HitsPerPage.js.snap deleted file mode 100644 index 74ec1ccaea..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/HitsPerPage.js.snap +++ /dev/null @@ -1,51 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`HitsPerPage renders 1`] = ` -
    - -
    -`; - -exports[`HitsPerPage renders with a custom className 1`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/InfiniteHits.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/InfiniteHits.js.snap deleted file mode 100644 index bb3f6c8984..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/InfiniteHits.js.snap +++ /dev/null @@ -1,79 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`InfiniteHits accepts a custom className 1`] = ` -
    -
      -
    • -
      - {"objectID":0} -
      -
    • -
    • -
      - {"objectID":1} -
      -
    • -
    • -
      - {"objectID":2} -
      -
    • -
    - -
    -`; - -exports[`InfiniteHits accepts a hitComponent prop 1`] = ` -
    -
      -
    • -
      - {"objectID":0} -
      -
    • -
    • -
      - {"objectID":1} -
      -
    • -
    • -
      - {"objectID":2} -
      -
    • -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/List.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/List.js.snap deleted file mode 100644 index 657a88ee98..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/List.js.snap +++ /dev/null @@ -1,206 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`List expect to render a list of items 1`] = ` -
    -
      -
    • - - Apple - -
    • -
    • - - Samsung - -
    • -
    • - - Microsoft - -
    • -
    -
    -`; - -exports[`List expect to render a list of nested items 1`] = ` -
    -
      -
    • - - Apple - -
        -
      • - - iPhone - -
      • -
      • - - iPad - -
      • -
      -
    • -
    • - - Samsung - -
        -
      • - - S8 - -
      • -
      • - - Note 5 - -
      • -
      -
    • -
    • - - Microsoft - -
        -
      • - - Surface - -
      • -
      • - - Surface Pro - -
      • -
      -
    • -
    -
    -`; - -exports[`List expect to render a list of nested items with empty children 1`] = ` -
    -
      -
    • - - Apple - -
        -
      • - - iPhone - -
      • -
      • - - iPad - -
      • -
      -
    • -
    • - - Samsung - -
        -
      • - - S8 - -
      • -
      • - - Note 5 - -
      • -
      -
    • -
    • - - Microsoft - -
    • -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Menu.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Menu.js.snap deleted file mode 100644 index 6e8ca2cf36..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Menu.js.snap +++ /dev/null @@ -1,489 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Menu Menu with search inside items but no search results 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    - -
    -`; - -exports[`Menu Menu with search inside items with search results 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    - -
    -`; - -exports[`Menu applies translations 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    - - -
    -`; - -exports[`Menu default menu 1`] = ` - -`; - -exports[`Menu default menu with custom className 1`] = ` - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/MenuSelect.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/MenuSelect.js.snap deleted file mode 100644 index 79213421d1..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/MenuSelect.js.snap +++ /dev/null @@ -1,212 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MenuSelect applies translations 1`] = ` -
    - -
    -`; - -exports[`MenuSelect default menu select 1`] = ` -
    - -
    -`; - -exports[`MenuSelect default menu select with custom className 1`] = ` -
    - -
    -`; - -exports[`MenuSelect default menu select with no refinement 1`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/NumericMenu.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/NumericMenu.js.snap deleted file mode 100644 index e2f377760d..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/NumericMenu.js.snap +++ /dev/null @@ -1,445 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`NumericMenu no refinements 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; - -exports[`NumericMenu supports having a selected item 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; - -exports[`NumericMenu supports passing custom className 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; - -exports[`NumericMenu supports passing items values 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Pagination.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Pagination.js.snap deleted file mode 100644 index 57dc5dc343..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Pagination.js.snap +++ /dev/null @@ -1,2919 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Pagination allows toggling display of the first page button on and off 1`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the first page button on and off 2`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the last page button on and off 1`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the last page button on and off 2`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the next page button on and off 1`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the next page button on and off 2`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the previous page button on and off 1`] = ` -
    - -
    -`; - -exports[`Pagination allows toggling display of the previous page button on and off 2`] = ` -
    - -
    -`; - -exports[`Pagination applies its default props 1`] = ` -
    - -
    -`; - -exports[`Pagination applies its default props with custom className 1`] = ` -
    - -
    -`; - -exports[`Pagination applies its default props without refinement 1`] = ` -
    - -
    -`; - -exports[`Pagination disabled all button if no results 1`] = ` -
    -
      -
    • - - « - -
    • -
    • - - ‹ - -
    • -
    • - - › - -
    • -
    • - - » - -
    • -
    -
    -`; - -exports[`Pagination displays the correct padding of links 1`] = ` -
    - -
    -`; - -exports[`Pagination displays the correct padding of links 2`] = ` -
    - -
    -`; - -exports[`Pagination displays the correct padding of links 3`] = ` -
    - -
    -`; - -exports[`Pagination displays the correct padding of links 4`] = ` -
    - -
    -`; - -exports[`Pagination indicates when first button is relevant 1`] = ` -
    - -
    -`; - -exports[`Pagination indicates when first button is relevant 2`] = ` -
    - -
    -`; - -exports[`Pagination lets you customize its theme 1`] = ` -
    - -
    -`; - -exports[`Pagination lets you customize its translations 1`] = ` - -`; - -exports[`Pagination lets you force a maximum of pages 1`] = ` -
    - -
    -`; - -exports[`Pagination lets you force a maximum of pages 2`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Panel.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Panel.js.snap deleted file mode 100644 index 044f0bb356..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Panel.js.snap +++ /dev/null @@ -1,149 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Panel expect to render 1`] = ` -
    -
    - -
    - Hello content -
    -
    -
    -
    -`; - -exports[`Panel expect to render when setCanRefine is called 1`] = ` - -
    -
    - -
    -
    -
    -`; - -exports[`Panel expect to render when setCanRefine is called 2`] = ` - -
    -
    - -
    -
    -
    -`; - -exports[`Panel expect to render with custom className 1`] = ` -
    -
    - -
    - Hello content -
    -
    -
    -
    -`; - -exports[`Panel expect to render with footer 1`] = ` -
    -
    - -
    - Hello content -
    -
    -
    -
    -

    - Footer -

    -
    -
    -`; - -exports[`Panel expect to render with header 1`] = ` -
    -
    -

    - Header -

    -
    -
    - -
    - Hello content -
    -
    -
    -
    -`; - -exports[`Panel expect to render without refinement 1`] = ` -
    -
    - -
    - Hello content -
    -
    -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/PoweredBy.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/PoweredBy.js.snap deleted file mode 100644 index 239022d11a..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/PoweredBy.js.snap +++ /dev/null @@ -1,97 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`PoweredBy applies translations 1`] = ` -
    - - Search By - - - - - - - -
    -`; - -exports[`PoweredBy default 1`] = ` -
    - - Search by - - - - - - - -
    -`; - -exports[`PoweredBy default with className 1`] = ` -
    - - Search by - - - - - - - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/QueryRuleCustomData.tsx.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/QueryRuleCustomData.tsx.snap deleted file mode 100644 index e203e7a623..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/QueryRuleCustomData.tsx.snap +++ /dev/null @@ -1,36 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`QueryRuleCustomData expects to render multiple items 1`] = ` -
    -
    - Image 1 -
    -
    - Image 2 -
    -
    -`; - -exports[`QueryRuleCustomData expects to render the empty container with empty items 1`] = ` -
    -`; - -exports[`QueryRuleCustomData expects to render with custom className 1`] = ` -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RangeInput.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RangeInput.js.snap deleted file mode 100644 index e18e3e8e54..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RangeInput.js.snap +++ /dev/null @@ -1,586 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RangeInput render with translations 1`] = ` -
    -
    - - - SEPARATOR - - - -
    -
    -`; - -exports[`RawRangeInput onChange expect to update max onChange 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput onChange expect to update min onChange 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render when can't refine 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with custom className 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with empty values 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with empty values when refinement is equal to min / max 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with max only 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with min / max 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with min only 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with precision of 1 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with precision of 2 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; - -exports[`RawRangeInput render with refinement 1`] = ` -
    -
    - - - separator - - - -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RatingMenu.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RatingMenu.js.snap deleted file mode 100644 index 787e1c4bbd..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RatingMenu.js.snap +++ /dev/null @@ -1,2597 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RatingMenu applies translations 1`] = ` - -`; - -exports[`RatingMenu expect to render from from 1 when min is negative 1`] = ` - -`; - -exports[`RatingMenu expect to render nothing when min is higher than max 1`] = ` -
    - - - - - - - - -
      -
    -`; - -exports[`RatingMenu expect to render when only max is defined 1`] = ` - -`; - -exports[`RatingMenu expect to render without refinement 1`] = ` - -`; - -exports[`RatingMenu supports passing custom className 1`] = ` - -`; - -exports[`RatingMenu supports passing max/min values 1`] = ` - -`; - -exports[`RatingMenu supports passing max/min values smaller than count max & min 1`] = ` - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RefinementList.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RefinementList.js.snap deleted file mode 100644 index b3fa1eaef4..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/RefinementList.js.snap +++ /dev/null @@ -1,615 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RefinementList applies translations 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; - -exports[`RefinementList default refinement list 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    - -
    -`; - -exports[`RefinementList default refinement list with custom className 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    - -
    -`; - -exports[`RefinementList default refinement list with no refinement 1`] = ` -
    -
      -
    • - -
    • -
    • - -
    • -
    - -
    -`; - -exports[`RefinementList refinement list with search inside items but no search results 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    -
      -
    • - -
    • -
    • - -
    • -
    • - -
    • -
    -
    -`; - -exports[`RefinementList refinement list with search inside items with search results 1`] = ` -
    -
    -
    -
    - - - -
    -
    -
    -
      -
    • - -
    • -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ScrollTo.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ScrollTo.js.snap deleted file mode 100644 index 4b8d2bb38e..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/ScrollTo.js.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`ScrollTo expect to render 1`] = ` -
    - content -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SearchBox.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SearchBox.js.snap deleted file mode 100644 index 2b7935ce80..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SearchBox.js.snap +++ /dev/null @@ -1,743 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SearchBox applies its default props 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox applies its default props with custom className 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox lets you customize its theme 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox lets you customize its translations 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox lets you give custom components for reset and submit 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox should render the loader if showLoadingIndicator is true 1`] = ` -
    -
    - - - - -
    -
    -`; - -exports[`SearchBox should render the loader if showLoadingIndicator is true 2`] = ` -
    -
    - - - - -
    -
    -`; - -exports[`SearchBox transfers the autoFocus prop to the underlying input element 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox treats its query prop as its input value 1`] = ` -
    -
    - - - -
    -
    -`; - -exports[`SearchBox treats its query prop as its input value 2`] = ` -
    -
    - - - -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Snippet.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Snippet.js.snap deleted file mode 100644 index 9f713bcb09..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/Snippet.js.snap +++ /dev/null @@ -1,97 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Snippet parses an highlighted snippet attribute of hit object 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; - -exports[`Snippet renders a hit with a custom className 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; - -exports[`Snippet renders a hit with a custom tag correctly 1`] = ` - - - awesome - - - hi - - - ghlighted - - - hi - - - t! - - -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SortBy.js.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SortBy.js.snap deleted file mode 100644 index 951d935259..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/SortBy.js.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SortBy expect to render with custom className 1`] = ` -
    - - - toggle the refinement - - -
    -`; - -exports[`ToggleRefinement expect to render with a negative currentRefinement 1`] = ` -
    - -
    -`; - -exports[`ToggleRefinement expect to render with a positive currentRefinement 1`] = ` -
    - -
    -`; - -exports[`ToggleRefinement expect to render with custom className 1`] = ` -
    - -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/VoiceSearch.tsx.snap b/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/VoiceSearch.tsx.snap deleted file mode 100644 index 6d9e612fa0..0000000000 --- a/packages/react-instantsearch-dom/src/components/__tests__/__snapshots__/VoiceSearch.tsx.snap +++ /dev/null @@ -1,111 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`VoiceSearch Rendering with custom template for status 1`] = ` -
    - -
    -

    - status: - recognizing -

    -

    - errorCode: -

    -

    - isListening: - true -

    -

    - transcript: - Hello -

    -

    - isSpeechFinal: - false -

    -

    - isBrowserSupported: - true -

    -
    -
    -
    -`; - -exports[`VoiceSearch Rendering with default props 1`] = ` - - -
    - -
    - -

    - -

    -
    -
    -
    -`; diff --git a/packages/react-instantsearch-dom/src/components/index.js b/packages/react-instantsearch-dom/src/components/index.js deleted file mode 100644 index 2ca115c7ec..0000000000 --- a/packages/react-instantsearch-dom/src/components/index.js +++ /dev/null @@ -1,18 +0,0 @@ -export { default as CurrentRefinements } from './CurrentRefinements'; -export { default as HierarchicalMenu } from './HierarchicalMenu'; -export { default as Hits } from './Hits'; -export { default as HitsPerPage } from './HitsPerPage'; -export { default as Menu } from './Menu'; -export { default as NumericMenu } from './NumericMenu'; -export { default as Pagination } from './Pagination'; -export { default as PoweredBy } from './PoweredBy'; -export { default as RangeInput } from './RangeInput'; -export { default as RatingMenu } from './RatingMenu'; -export { default as RefinementList } from './RefinementList'; -export { default as ClearRefinements } from './ClearRefinements'; -export { default as ScrollTo } from './ScrollTo'; -export { default as SearchBox } from './SearchBox'; -export { default as RelevantSort } from './RelevantSort'; -export { default as SortBy } from './SortBy'; -export { default as Stats } from './Stats'; -export { default as ToggleRefinement } from './ToggleRefinement'; diff --git a/packages/react-instantsearch-dom/src/core/__tests__/createInstantSearchServer.js b/packages/react-instantsearch-dom/src/core/__tests__/createInstantSearchServer.js deleted file mode 100644 index 1051daf589..0000000000 --- a/packages/react-instantsearch-dom/src/core/__tests__/createInstantSearchServer.js +++ /dev/null @@ -1,1255 +0,0 @@ -import Adapter from '@wojtekmaj/enzyme-adapter-react-17'; -import { SearchParameters } from 'algoliasearch-helper'; -import Enzyme from 'enzyme'; -import React from 'react'; -import { - Index, - InstantSearch, - DynamicWidgets, - createConnector, - version, - connectRefinementList, -} from 'react-instantsearch-core'; -import { SearchBox } from 'react-instantsearch-dom'; - -import { findResultsState } from '../createInstantSearchServer'; - -Enzyme.configure({ adapter: new Adapter() }); - -describe('findResultsState', () => { - const createSearchClient = ({ transformResponseParams } = {}) => ({ - search: jest.fn((requests) => - Promise.resolve({ - results: requests.map(({ indexName, params: { query } }) => ({ - query, - hits: [], - renderingContent: { - facetOrdering: { - facets: { - order: ['brand', 'hierarchicalCategories.lvl0', 'categories'], - }, - values: { - brand: { - sortRemainingBy: 'count', - }, - categories: { - sortRemainingBy: 'count', - }, - 'hierarchicalCategories.lvl0': { - sortRemainingBy: 'count', - }, - }, - }, - }, - params: transformResponseParams - ? transformResponseParams(query) - : `query=${encodeURIComponent(query)}`, - index: indexName, - })), - }) - ), - }); - - const createWidget = ({ getSearchParameters = () => {} } = {}) => - createConnector({ - displayName: 'CoolConnector', - getProvidedProps: () => null, - getSearchParameters(searchParameters, props, searchState) { - getSearchParameters(); - - const fallback = props.defaultRefinement || 'Apple'; - - if (this.props.indexContextValue) { - const index = this.props.indexContextValue.targetedIndex; - const indexSearchState = - searchState.indices && searchState.indices[index] - ? searchState.indices[index] - : {}; - - return searchParameters.setQuery(indexSearchState.query || fallback); - } - - return searchParameters.setQuery(searchState.query || fallback); - }, - getMetadata(props, searchState) { - return { id: 'cool', props, searchState }; - }, - getId: () => 'id', - })(() => null); - - const requiredProps = { - indexName: 'indexName', - searchClient: createSearchClient({}), - }; - - it('throws an error if props are not provided', () => { - const App = () =>
    ; - - const trigger = () => findResultsState(App); - - expect(() => trigger()).toThrowErrorMatchingInlineSnapshot( - `"The function \`findResultsState\` must be called with props: \`findResultsState(App, props)\`"` - ); - }); - - it('throws an error if props does not have a `searchClient`', () => { - const App = () =>
    ; - - const props = {}; - - const trigger = () => findResultsState(App, props); - - expect(() => trigger()).toThrowErrorMatchingInlineSnapshot( - `"The props provided to \`findResultsState\` must have a \`searchClient\`"` - ); - }); - - it('throws an error if props does not have an `indexName`', () => { - const App = () =>
    ; - - const props = { - searchClient: createSearchClient({}), - }; - - const trigger = () => findResultsState(App, props); - - expect(() => trigger()).toThrowErrorMatchingInlineSnapshot( - `"The props provided to \`findResultsState\` must have an \`indexName\`"` - ); - }); - - it('adds expected Algolia agents', () => { - const App = (props) => ( - - - - ); - - const searchClient = { - ...createSearchClient({}), - addAlgoliaAgent: jest.fn(), - }; - - const props = { - ...requiredProps, - searchClient, - }; - - findResultsState(App, props); - - // The `addAlgoliaAgent` method is called 7 times: - // - 1 times with react-instantsearch-dom/server - // - 2 times with react-instantsearch-core/InstantSearch - // - 4 times with the AlgoliasearchHelper - - expect(searchClient.addAlgoliaAgent).toHaveBeenCalledTimes(7); - expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( - `react (${React.version})` - ); - expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch (${version})` - ); - expect(searchClient.addAlgoliaAgent).toHaveBeenCalledWith( - `react-instantsearch-server (${version})` - ); - }); - - it('does not throw if `searchClient` does not have a `addAlgoliaAgent()` method', () => { - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({}), - }; - - const trigger = () => findResultsState(App, props); - - expect(() => trigger()).not.toThrow(); - }); - - it('throws if no widgets are added', () => { - const App = (props) => ; - - const props = { - ...requiredProps, - searchClient: createSearchClient({}), - }; - - expect(() => - findResultsState(App, props) - ).toThrowErrorMatchingInlineSnapshot( - `"[ssr]: no widgets were added, you likely did not pass the \`widgetsCollector\` down to the InstantSearch component."` - ); - }); - - describe('single index', () => { - it('results should be state & results', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - }; - - const results = await findResultsState(App, props); - - expect(results).toEqual({ - metadata: [expect.objectContaining({ id: 'cool' })], - state: expect.any(SearchParameters), - rawResults: expect.arrayContaining([ - expect.objectContaining({ query: expect.any(String) }), - ]), - }); - }); - - it('searchParameters should be cleaned each time', async () => { - const getSearchParameters = jest.fn(); - const Connected = createWidget({ - getSearchParameters, - }); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - }; - - await findResultsState(App, props); - - expect(getSearchParameters).toHaveBeenCalledTimes(1); - - getSearchParameters.mockClear(); - - await findResultsState(App, props); - - expect(getSearchParameters).toHaveBeenCalledTimes(1); - }); - - it('without search state', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - }; - - const data = await findResultsState(App, props); - - expect(data).toEqual({ - metadata: [expect.objectContaining({ id: 'cool' })], - rawResults: [ - expect.objectContaining({ index: 'indexName', query: 'Apple' }), - ], - state: expect.objectContaining({ index: 'indexName', query: 'Apple' }), - }); - }); - - it('with search state', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchState: { - query: 'iPhone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data).toEqual({ - metadata: [expect.objectContaining({ id: 'cool' })], - rawResults: [ - expect.objectContaining({ index: 'indexName', query: 'iPhone' }), - ], - state: expect.objectContaining({ index: 'indexName', query: 'iPhone' }), - }); - }); - - it('forwards metadata', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchState: { - query: 'godlike', - }, - }; - - const results = await findResultsState(App, props); - - expect(results).toEqual({ - metadata: [ - { - id: 'cool', - props: expect.objectContaining({ prop: 'something' }), - searchState: { query: 'godlike' }, - }, - ], - state: expect.any(SearchParameters), - rawResults: expect.arrayContaining([ - expect.objectContaining({ query: expect.any(String) }), - ]), - }); - }); - - describe('cleaning "params"', () => { - it('with one query', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({}), - searchState: { - query: 'iPhone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone"` - ); - }); - - it('with custom client, without "params"', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams() { - return undefined; - }, - }), - searchState: { - query: 'iPhone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toBeUndefined(); - }); - - it('with shadowing query', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({}), - searchState: { - query: 'iPhone&query=iphone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone%26query%3Diphone"` - ); - }); - - it('with modified query', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: (query) => - `query=${encodeURIComponent(query)}&query=modified`, - }), - searchState: { - query: 'iPhone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone"` - ); - }); - - it('with shadowing query and modified query', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: (query) => - `query=${encodeURIComponent(query)}&query=modified`, - }), - searchState: { - query: 'iPhone&query=iphone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone%26query%3Diphone"` - ); - }); - - it('with padded, modified query', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: (query) => - `test=1&query=${encodeURIComponent(query)}&boo=ba&query=modified`, - }), - searchState: { - query: 'iPhone&query=iphone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot( - `"test=1&query=iPhone%26query%3Diphone&boo=ba"` - ); - }); - - it('with nothing returned', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: () => '', - }), - searchState: { - query: 'iPhone&query=iphone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot(`""`); - }); - - it('with no query returned', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: () => 'lol=lol', - }), - searchState: { - query: 'iPhone&query=iphone', - }, - }; - - const data = await findResultsState(App, props); - - expect(data.rawResults[0].params).toMatchInlineSnapshot(`"lol=lol"`); - }); - }); - - it('searches twice (cached) with dynamic widgets', async () => { - const RefinementList = connectRefinementList(() => null); - const App = (props) => ( - - - - ); - - const props = { - searchClient: createSearchClient({}), - indexName: 'abc', - searchState: { - query: 'iPhone', - }, - }; - - await findResultsState(App, props); - - expect(props.searchClient.search).toHaveBeenCalledTimes(2); - // both calls are the same, so they're cached - expect(props.searchClient.search.mock.calls[0][0]).toEqual( - props.searchClient.search.mock.calls[1][0] - ); - }); - - it('searches twice with dynamic widgets and a refinement', async () => { - const RefinementList = connectRefinementList(() => null); - const App = (props) => ( - - - - ); - - const props = { - searchClient: createSearchClient({}), - indexName: 'instant_search', - searchState: { - query: 'iPhone', - refinementList: { categories: ['refined!'] }, - }, - }; - - await findResultsState(App, props); - - expect(props.searchClient.search).toHaveBeenCalledTimes(2); - - // first query doesn't have the fallback widget mounted yet - expect(props.searchClient.search.mock.calls[0][0][0]).toEqual({ - indexName: 'instant_search', - params: { - facets: ['*'], - highlightPostTag: '', - highlightPreTag: '', - maxValuesPerFacet: 20, - tagFilters: '', - }, - }); - - // second query does have the fallback widget mounted, and thus also the refinement - expect(props.searchClient.search.mock.calls[1][0][0]).toEqual({ - indexName: 'instant_search', - params: { - facetFilters: [['categories:refined!']], - facets: ['*'], - highlightPostTag: '', - highlightPreTag: '', - maxValuesPerFacet: 20, - tagFilters: '', - }, - }); - }); - }); - - describe('multi index', () => { - it('results should be instance of SearchResults and SearchParameters', async () => { - const Connected = createWidget(); - - const App = (props) => ( - - - - - - ); - - const props = { - ...requiredProps, - }; - - const { results } = await findResultsState(App, props); - - results.forEach((result) => { - expect(result.state).toBeInstanceOf(SearchParameters); - expect(result.rawResults).toBeInstanceOf(Array); - }); - }); - - it('searchParameters should be cleaned each time', async () => { - const getSearchParameters = jest.fn(); - const Connected = createWidget({ - getSearchParameters, - }); - - const App = (props) => ( - - - - - - ); - - const props = { - ...requiredProps, - }; - - await findResultsState(App, props); - - expect(getSearchParameters).toHaveBeenCalledTimes(1); - - getSearchParameters.mockClear(); - - await findResultsState(App, props); - - expect(getSearchParameters).toHaveBeenCalledTimes(1); - }); - - it('without search state - first API', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - }; - - const data = await findResultsState(App, props); - - expect(data.results).toHaveLength(2); - - const { metadata, results } = data; - const [first, second] = results; - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'Apple' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'Apple' }), - ], - }); - - expect(second).toEqual({ - _internalIndexId: 'index2', - state: expect.objectContaining({ index: 'index2', query: 'Apple' }), - rawResults: [ - expect.objectContaining({ index: 'index2', query: 'Apple' }), - ], - }); - }); - - it('without search state - second API', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'Apple' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'Apple' }), - ], - }); - - expect(second).toEqual({ - _internalIndexId: 'index2', - state: expect.objectContaining({ index: 'index2', query: 'Apple' }), - rawResults: [ - expect.objectContaining({ index: 'index2', query: 'Apple' }), - ], - }); - }); - - it('without search state - same index', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'Apple' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'Apple' }), - ], - }); - - expect(second).toEqual({ - _internalIndexId: 'index1_with_refinement', - state: expect.objectContaining({ index: 'index1', query: 'iWatch' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iWatch' }), - ], - }); - }); - - it('with search state - first API', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - searchState: { - indices: { - index1: { - query: 'iPhone', - }, - index2: { - query: 'iPad', - }, - }, - }, - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'iPhone' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPhone' }), - ], - }); - - expect(second).toEqual({ - _internalIndexId: 'index2', - state: expect.objectContaining({ index: 'index2', query: 'iPad' }), - rawResults: [ - expect.objectContaining({ index: 'index2', query: 'iPad' }), - ], - }); - }); - - it('with search state - second API', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - searchState: { - query: 'iPhone', - indices: { - index2: { - query: 'iPad', - }, - }, - }, - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'iPhone' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPhone' }), - ], - }); - - expect(second).toEqual({ - _internalIndexId: 'index2', - state: expect.objectContaining({ index: 'index2', query: 'iPad' }), - rawResults: [ - expect.objectContaining({ index: 'index2', query: 'iPad' }), - ], - }); - }); - - it('with search state - same index', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - ); - - const props = { - ...requiredProps, - indexName: 'index1', - searchState: { - query: 'iPhone', - indices: { - index1WithRefinement: { - query: 'iPad', - }, - }, - }, - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - expect.objectContaining({ id: 'cool' }), - expect.objectContaining({ id: 'cool' }), - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'iPhone' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPhone' }), - ], - }); - expect(second).toEqual({ - _internalIndexId: 'index1WithRefinement', - state: expect.objectContaining({ index: 'index1', query: 'iPad' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPad' }), - ], - }); - }); - - it('forwards metadata', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - ); - - const searchState = { - query: 'iPhone', - indices: { - index1WithRefinement: { - query: 'iPad', - }, - }, - }; - - const props = { - ...requiredProps, - indexName: 'index1', - searchState, - }; - - const { results, metadata } = await findResultsState(App, props); - - expect(metadata).toEqual([ - { - id: 'cool', - searchState, - props: expect.objectContaining({ prop: 'value1' }), - }, - { - id: 'cool', - searchState, - props: expect.objectContaining({ prop: 'value2' }), - }, - ]); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first).toEqual({ - _internalIndexId: 'index1', - state: expect.objectContaining({ index: 'index1', query: 'iPhone' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPhone' }), - ], - }); - expect(second).toEqual({ - _internalIndexId: 'index1WithRefinement', - state: expect.objectContaining({ index: 'index1', query: 'iPad' }), - rawResults: [ - expect.objectContaining({ index: 'index1', query: 'iPad' }), - ], - }); - }); - - describe('cleaning "params"', () => { - it('multiple queries', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({}), - indexName: 'index1', - searchState: { - query: 'iPhone', - indices: { - index1WithRefinement: { - query: 'iPad&query=test', - }, - }, - }, - }; - - const { results } = await findResultsState(App, props); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone"` - ); - expect(second.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPad%26query%3Dtest"` - ); - }); - - it('custom client without "params"', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams() { - return undefined; - }, - }), - indexName: 'index1', - searchState: { - query: 'iPhone', - indices: { - index1WithRefinement: { - query: 'iPad&query=test', - }, - }, - }, - }; - - const { results } = await findResultsState(App, props); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first.rawResults[0].params).toBeUndefined(); - expect(second.rawResults[0].params).toBeUndefined(); - }); - - it('server-side params', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - ); - - const props = { - ...requiredProps, - searchClient: createSearchClient({ - transformResponseParams: (query) => - `query=${encodeURIComponent(query)}&query=modified`, - }), - indexName: 'index1', - searchState: { - query: 'iPhone', - indices: { - index1WithRefinement: { - query: 'iPad&query=test', - }, - }, - }, - }; - - const { results } = await findResultsState(App, props); - - expect(results).toHaveLength(2); - - const [first, second] = results; - - expect(first.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPhone"` - ); - expect(second.rawResults[0].params).toMatchInlineSnapshot( - `"query=iPad%26query%3Dtest"` - ); - }); - }); - - it('searches once with multiple indices', async () => { - const Connected = createWidget(); - const App = (props) => ( - - - - - - - - - - ); - - const props = { - searchClient: createSearchClient({}), - indexName: 'abc', - searchState: { - query: 'iPhone', - }, - }; - - const { results } = await findResultsState(App, props); - - expect(props.searchClient.search).toHaveBeenCalledTimes(1); - expect(results.map(({ _internalIndexId }) => _internalIndexId)).toEqual([ - 'abc', - 'index1WithRefinement', - 'index2WithRefinement', - ]); - }); - - it('searches twice (cached) with dynamic widgets', async () => { - const RefinementList = connectRefinementList(() => null); - const App = (props) => ( - - - - - - ); - - const props = { - searchClient: createSearchClient({}), - indexName: 'abc', - searchState: { - query: 'iPhone', - }, - }; - - await findResultsState(App, props); - - // [search, dynamic] - expect(props.searchClient.search).toHaveBeenCalledTimes(2); - - // both calls are the same, so they're cached - expect(props.searchClient.search.mock.calls[0][0]).toEqual( - props.searchClient.search.mock.calls[1][0] - ); - }); - - it('searches twice with dynamic widgets and a refinement', async () => { - const RefinementList = connectRefinementList(() => null); - const App = (props) => ( - - - - - - ); - - const props = { - searchClient: createSearchClient({}), - indexName: 'instant_search', - searchState: { - query: 'iPhone', - indices: { - index1WithRefinement: { - refinementList: { categories: ['refined!'] }, - }, - }, - }, - }; - - await findResultsState(App, props); - - // [search, dynamic] - expect(props.searchClient.search).toHaveBeenCalledTimes(2); - - // first query doesn't have the fallback widget mounted yet - expect(props.searchClient.search.mock.calls[0][0][1]).toEqual({ - indexName: 'index1WithRefinement', - params: { - facets: ['*'], - highlightPostTag: '', - highlightPreTag: '', - maxValuesPerFacet: 20, - tagFilters: '', - }, - }); - - // second query does have the fallback widget mounted, and thus also the refinement - expect(props.searchClient.search.mock.calls[1][0][1]).toEqual({ - indexName: 'index1WithRefinement', - params: { - facetFilters: [['categories:refined!']], - facets: ['*'], - highlightPostTag: '', - highlightPreTag: '', - maxValuesPerFacet: 20, - tagFilters: '', - }, - }); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/core/__tests__/getInsightsAnonymousUserToken.ts b/packages/react-instantsearch-dom/src/core/__tests__/getInsightsAnonymousUserToken.ts deleted file mode 100644 index 1a914f6622..0000000000 --- a/packages/react-instantsearch-dom/src/core/__tests__/getInsightsAnonymousUserToken.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import getInsightsAnonymousUserToken, { - ANONYMOUS_TOKEN_COOKIE_KEY, -} from '../getInsightsAnonymousUserToken'; - -const DAY = 86400000; /* 1 day in ms*/ -const DATE_TOMORROW = new Date(Date.now() + DAY).toUTCString(); -const DATE_YESTERDAY = new Date(Date.now() - DAY).toUTCString(); - -const resetCookie = (cookieKey: string) => { - document.cookie = `${cookieKey}=;expires=Thu, 01-Jan-1970 00:00:01 GMT;`; -}; - -describe('getInsightsAnonymousUserToken', () => { - beforeEach(() => { - resetCookie(ANONYMOUS_TOKEN_COOKIE_KEY); - }); - - it('should return undefined when no cookies', () => { - expect(getInsightsAnonymousUserToken()).toBe(undefined); - }); - - it('should return undefined when cookie present but expired', () => { - document.cookie = `${ANONYMOUS_TOKEN_COOKIE_KEY}=anonymous-uuid;expires=${DATE_YESTERDAY};`; - expect(getInsightsAnonymousUserToken()).toBe(undefined); - }); - - it('should return the anonymous uuid when cookie present and valid', () => { - document.cookie = `${ANONYMOUS_TOKEN_COOKIE_KEY}=anonymous-uuid;expires=${DATE_TOMORROW};`; - expect(getInsightsAnonymousUserToken()).toBe('anonymous-uuid'); - }); - - it('should return the anonymous uuid when other cookies are invalid', () => { - document.cookie = `${ANONYMOUS_TOKEN_COOKIE_KEY}=anonymous-uuid;expires=${DATE_TOMORROW};`; - document.cookie = `BAD_COOKIE=val%ue;expires=${DATE_TOMORROW};path=/`; - expect(getInsightsAnonymousUserToken()).toBe('anonymous-uuid'); - }); -}); diff --git a/packages/react-instantsearch-dom/src/core/__tests__/utils.js b/packages/react-instantsearch-dom/src/core/__tests__/utils.js deleted file mode 100644 index d850eec7e1..0000000000 --- a/packages/react-instantsearch-dom/src/core/__tests__/utils.js +++ /dev/null @@ -1,110 +0,0 @@ -import * as utils from '../utils'; - -describe('utils', () => { - describe('createClassNames', () => { - it('expect to return classNames', () => { - const cx = utils.createClassNames('Widget'); - - const actual = cx('', null, undefined, false, 'one', 'two').split(' '); - const expectation = ['ais-Widget', 'ais-Widget-one', 'ais-Widget-two']; - - expect(actual).toEqual(expectation); - }); - - it('expect to return classNames with custom prefix', () => { - const cx = utils.createClassNames('Widget', 'ris'); - - const actual = cx('', null, undefined, false, 'one', 'two').split(' '); - const expectation = ['ris-Widget', 'ris-Widget-one', 'ris-Widget-two']; - - expect(actual).toEqual(expectation); - }); - }); - - describe('isSpecialClick', () => { - it('returns true if a modifier key is pressed', () => { - expect(utils.isSpecialClick({ altKey: true })).toBe(true); - expect(utils.isSpecialClick({ ctrlKey: true })).toBe(true); - expect(utils.isSpecialClick({ metaKey: true })).toBe(true); - expect(utils.isSpecialClick({ shiftKey: true })).toBe(true); - }); - - it("returns true if it's a middle click", () => { - expect(utils.isSpecialClick({ button: 1 })).toBe(true); - }); - - it('returns false otherwise', () => { - expect(utils.isSpecialClick({})).toBe(false); - }); - }); - - describe('capitalize', () => { - it('capitalizes a string', () => { - expect(utils.capitalize('oooh spooky')).toBe('Oooh spooky'); - }); - - it('works with empty strings', () => { - expect(utils.capitalize('')).toBe(''); - }); - }); - - describe('range', () => { - test('with end', () => { - expect(utils.range({ end: 4 })).toEqual([0, 1, 2, 3]); - }); - - test('with start and end', () => { - expect(utils.range({ start: 1, end: 5 })).toEqual([1, 2, 3, 4]); - }); - - test('with end and step', () => { - expect(utils.range({ end: 20, step: 5 })).toEqual([0, 5, 10, 15]); - }); - - test('rounds decimal array lengths', () => { - // (5000 - 1) / 500 = 9.998 so we want the array length to be rounded to 10. - expect(utils.range({ start: 1, end: 5000, step: 500 })).toHaveLength(10); - expect(utils.range({ start: 1, end: 5000, step: 500 })).toEqual([ - 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000, - ]); - }); - }); - - describe('find', () => { - test('returns the first match based on the comparator', () => { - expect( - utils.find([1], () => { - return true; - }) - ).toBe(1); - expect( - utils.find([1, 2], () => { - return true; - }) - ).toBe(1); - - expect( - utils.find([{ nice: false }, { nice: true }], function (el) { - return el.nice; - }) - ).toEqual({ nice: true }); - }); - - test('returns undefined in non-found cases', () => { - expect( - utils.find([], () => { - return false; - }) - ).toBeUndefined(); - expect( - utils.find(undefined, () => { - return false; - }) - ).toBeUndefined(); - - expect(() => { - utils.find([1, 2, 3], undefined); - }).toThrow(); - }); - }); -}); diff --git a/packages/react-instantsearch-dom/src/core/createInstantSearchServer.js b/packages/react-instantsearch-dom/src/core/createInstantSearchServer.js deleted file mode 100644 index 2ef6a19cf6..0000000000 --- a/packages/react-instantsearch-dom/src/core/createInstantSearchServer.js +++ /dev/null @@ -1,213 +0,0 @@ -import algoliasearchHelper, { SearchParameters } from 'algoliasearch-helper'; -import React from 'react'; -import { renderToString } from 'react-dom/server'; -import { version, HIGHLIGHT_TAGS } from 'react-instantsearch-core'; - -const hasMultipleIndices = (context) => context && context.multiIndexContext; - -const getIndexId = (context) => - hasMultipleIndices(context) - ? context.multiIndexContext.targetedIndex - : context.ais.mainTargetedIndex; - -function createWidgetsCollector(accumulator) { - return (props) => { - accumulator.push({ - ...props, - index: getIndexId(props.context), - }); - }; -} - -function getMetadata(widgets) { - return widgets - .filter((widget) => widget.getMetadata) - .map((widget) => { - return widget.getMetadata(widget.props, widget.searchState); - }); -} - -const getSearchParameters = (indexName, widgets) => { - const sharedParameters = widgets - .filter((widget) => !hasMultipleIndices(widget.context)) - .reduce( - (acc, widget) => - widget.getSearchParameters(acc, widget.props, widget.searchState), - new algoliasearchHelper.SearchParameters({ - ...HIGHLIGHT_TAGS, - index: indexName, - }) - ); - - const derivedParameters = widgets - .filter((widget) => hasMultipleIndices(widget.context)) - .reduce((acc, widget) => { - const indexId = getIndexId(widget.context); - - return { - ...acc, - [indexId]: widget.getSearchParameters( - acc[indexId] || sharedParameters, - widget.props, - widget.searchState - ), - }; - }, {}); - - return { - sharedParameters, - derivedParameters, - }; -}; - -/** - * The engine can return params: "query=xxx&query=yyy" if e.g. a query rule modifies it. - * This however will cause us to miss the cache hydration, so we make sure to keep - * only the first query (always the one from the parameters). - * @param {string} params the parameters to clean - * @returns {string} the parameters without duplicate query - */ -function removeDuplicateQuery(params) { - if (!params) { - return params; - } - let hasFoundQuery = false; - const queryParamRegex = /&?query=[^&]*/g; - return params.replace(queryParamRegex, function replacer(match) { - if (hasFoundQuery) { - return ''; - } - hasFoundQuery = true; - return match; - }); -} - -function cleanRawResults(rawResults) { - return rawResults.map((res) => { - return { - ...res, - params: removeDuplicateQuery(res.params), - }; - }); -} - -const singleIndexSearch = (helper, parameters) => - helper.searchOnce(parameters).then((res) => ({ - rawResults: cleanRawResults(res.content._rawResults), - state: res.content._state, - })); - -const multiIndexSearch = ( - indexName, - client, - sharedParameters, - { [indexName]: mainParameters, ...derivedParameters } -) => { - const helper = algoliasearchHelper(client, indexName); - const indexIds = Object.keys(derivedParameters); - - const searches = [ - new SearchParameters({ ...sharedParameters, ...mainParameters }), - ...indexIds.map((indexId) => derivedParameters[indexId]), - ].map( - (params) => - new Promise((resolve) => - helper.derive(() => params).once('result', resolve) - ) - ); - - helper.searchOnlyWithDerivedHelpers(); - - // We attach `indexId` on the results to be able to reconstruct the object - // on the client side. We cannot rely on `state.index` anymore because we - // may have multiple times the same index. - return Promise.all(searches).then((results) => - [indexName, ...indexIds].map((indexId, i) => ({ - rawResults: cleanRawResults(results[i].results._rawResults), - state: results[i].results._state, - _internalIndexId: indexId, - })) - ); -}; - -export const findResultsState = function (App, props) { - if (!props) { - throw new Error( - 'The function `findResultsState` must be called with props: `findResultsState(App, props)`' - ); - } - - if (!props.searchClient) { - throw new Error( - 'The props provided to `findResultsState` must have a `searchClient`' - ); - } - - if (!props.indexName) { - throw new Error( - 'The props provided to `findResultsState` must have an `indexName`' - ); - } - - let widgets = []; - // eslint-disable-next-line no-shadow - function execute(props) { - widgets = []; - renderToString( - - ); - - if (widgets.length === 0) { - throw new Error( - '[ssr]: no widgets were added, you likely did not pass the `widgetsCollector` down to the InstantSearch component.' - ); - } - - const { sharedParameters, derivedParameters } = getSearchParameters( - props.indexName, - widgets - ); - - const metadata = getMetadata(widgets); - - const helper = algoliasearchHelper( - props.searchClient, - sharedParameters.index - ); - - if (typeof props.searchClient.addAlgoliaAgent === 'function') { - props.searchClient.addAlgoliaAgent( - `react-instantsearch-server (${version})` - ); - } - - if (Object.keys(derivedParameters).length === 0) { - return singleIndexSearch(helper, sharedParameters).then((res) => { - return { - metadata, - ...res, - }; - }); - } - - return multiIndexSearch( - props.indexName, - props.searchClient, - sharedParameters, - derivedParameters - ).then((results) => { - return { metadata, results }; - }); - } - - return execute(props).then((resultsState) => { - // requires another query to retrieve the dynamic widgets - // to render. - if ( - widgets.some((widget) => widget.displayName === 'AlgoliaDynamicWidgets') - ) { - return execute({ ...props, resultsState }); - } - return resultsState; - }); -}; diff --git a/packages/react-instantsearch-dom/src/core/getInsightsAnonymousUserToken.ts b/packages/react-instantsearch-dom/src/core/getInsightsAnonymousUserToken.ts deleted file mode 100644 index 65d48e4335..0000000000 --- a/packages/react-instantsearch-dom/src/core/getInsightsAnonymousUserToken.ts +++ /dev/null @@ -1,20 +0,0 @@ -export const ANONYMOUS_TOKEN_COOKIE_KEY = '_ALGOLIA'; - -function getCookie(name: string): string | undefined { - const prefix = `${name}=`; - const cookies = document.cookie.split(';'); - for (let i = 0; i < cookies.length; i++) { - let cookie = cookies[i]; - while (cookie.charAt(0) === ' ') { - cookie = cookie.substring(1); - } - if (cookie.indexOf(prefix) === 0) { - return cookie.substring(prefix.length, cookie.length); - } - } - return undefined; -} - -export default function getInsightsAnonymousUserToken(): string | undefined { - return getCookie(ANONYMOUS_TOKEN_COOKIE_KEY); -} diff --git a/packages/react-instantsearch-dom/src/core/utils.ts b/packages/react-instantsearch-dom/src/core/utils.ts deleted file mode 100644 index e74f43a0c5..0000000000 --- a/packages/react-instantsearch-dom/src/core/utils.ts +++ /dev/null @@ -1,68 +0,0 @@ -import cx from 'classnames'; - -export const createClassNames = - (block: string, prefix = 'ais') => - (...elements: string[]) => { - const suitElements = elements - .filter((element) => element || element === '') - .map((element) => { - const baseClassName = `${prefix}-${block}`; - - return element ? `${baseClassName}-${element}` : baseClassName; - }); - - return cx(suitElements); - }; - -export const isSpecialClick = (event: MouseEvent) => { - const isMiddleClick = event.button === 1; - return Boolean( - isMiddleClick || - event.altKey || - event.ctrlKey || - event.metaKey || - event.shiftKey - ); -}; - -export const capitalize = (key: string) => - key.length === 0 ? '' : `${key[0].toUpperCase()}${key.slice(1)}`; - -type RangeOptions = { - start?: number; - end: number; - step?: number; -}; - -// taken from InstantSearch.js/utils -export function range({ start = 0, end, step = 1 }: RangeOptions): number[] { - // We can't divide by 0 so we re-assign the step to 1 if it happens. - const limitStep = step === 0 ? 1 : step; - - // In some cases the array to create has a decimal length. - // We therefore need to round the value. - // Example: - // { start: 1, end: 5000, step: 500 } - // => Array length = (5000 - 1) / 500 = 9.998 - const arrayLength = Math.round((end - start) / limitStep); - - return [...Array(arrayLength)].map( - (_, current) => (start + current) * limitStep - ); -} - -export function find( - array: TItem[], - comparator: (item: TItem) => boolean -): TItem | undefined { - if (!Array.isArray(array)) { - return undefined; - } - - for (let i = 0; i < array.length; i++) { - if (comparator(array[i])) { - return array[i]; - } - } - return undefined; -} diff --git a/packages/react-instantsearch-dom/src/hooks/useAnswers.js b/packages/react-instantsearch-dom/src/hooks/useAnswers.js deleted file mode 100644 index ee502577f8..0000000000 --- a/packages/react-instantsearch-dom/src/hooks/useAnswers.js +++ /dev/null @@ -1,98 +0,0 @@ -import React, { useState, useEffect, useMemo, useContext } from 'react'; -import { instantSearchContext } from 'react-instantsearch-core'; - -import { createConcurrentSafePromise } from '../lib/createConcurrentSafePromise'; -import { debounce } from '../lib/debounce'; - -function hasReactHooks() { - // >= 16.8.0 - const [major, minor] = React.version.split('.').map(Number); - return major >= 17 || (major === 16 && minor >= 8); -} - -export default function useAnswers({ - searchClient, - queryLanguages, - attributesForPrediction, - nbHits, - renderDebounceTime = 100, - searchDebounceTime = 100, - ...extraParameters -}) { - if (!hasReactHooks()) { - throw new Error( - `\`Answers\` component and \`useAnswers\` hook require all React packages to be 16.8.0 or higher.` - ); - } - const context = useContext(instantSearchContext); - const [query, setQuery] = useState(context.store.getState().widgets.query); - const [index, setIndex] = useState(context.mainTargetedIndex); - const [isLoading, setIsLoading] = useState(false); - const [hits, setHits] = useState([]); - const runConcurrentSafePromise = useMemo( - () => createConcurrentSafePromise(), - [] - ); - const searchIndex = useMemo( - () => searchClient.initIndex(index), - [searchClient, index] - ); - if (!searchIndex.findAnswers) { - throw new Error( - '`Answers` component and `useAnswers` hook require `algoliasearch` to be 4.8.0 or higher.' - ); - } - - const debouncedSearch = useMemo(() => { - return debounce(searchIndex.findAnswers, searchDebounceTime); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [searchIndex]); - - useEffect(() => { - setIndex(context.mainTargetedIndex); - - return context.store.subscribe(() => { - const { widgets } = context.store.getState(); - setQuery(widgets.query); - }); - }, [context]); - - const setDebouncedResult = useMemo( - () => - debounce((result) => { - setIsLoading(false); - setHits(result.hits); - }, renderDebounceTime), - // eslint-disable-next-line react-hooks/exhaustive-deps - [setIsLoading, setHits] - ); - - const fetchAnswers = () => { - if (!query) { - setIsLoading(false); - setHits([]); - return; - } - setIsLoading(true); - runConcurrentSafePromise( - debouncedSearch(query, queryLanguages, { - ...extraParameters, - nbHits, - attributesForPrediction, - }) - ).then((result) => { - if (!result) { - // It's undefined when it's debounced. - return; - } - setDebouncedResult(result); - }); - }; - - useEffect(() => { - fetchAnswers(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [query]); - - return { hits, isLoading }; -} diff --git a/packages/react-instantsearch-dom/src/index.js b/packages/react-instantsearch-dom/src/index.js deleted file mode 100644 index 8063c74a1b..0000000000 --- a/packages/react-instantsearch-dom/src/index.js +++ /dev/null @@ -1,93 +0,0 @@ -// Core -export { createConnector } from 'react-instantsearch-core'; -export { HIGHLIGHT_TAGS } from 'react-instantsearch-core'; -export { translatable } from 'react-instantsearch-core'; - -// Widget -export { Configure } from 'react-instantsearch-core'; -export { ExperimentalConfigureRelatedItems } from 'react-instantsearch-core'; -export { QueryRuleContext } from 'react-instantsearch-core'; -export { Index } from 'react-instantsearch-core'; -export { InstantSearch } from 'react-instantsearch-core'; - -// Connectors -export { connectAutoComplete } from 'react-instantsearch-core'; -export { connectBreadcrumb } from 'react-instantsearch-core'; -export { connectConfigure } from 'react-instantsearch-core'; -export { EXPERIMENTAL_connectConfigureRelatedItems } from 'react-instantsearch-core'; -export { connectCurrentRefinements } from 'react-instantsearch-core'; -export { - connectDynamicWidgets, - EXPERIMENTAL_connectDynamicWidgets, -} from 'react-instantsearch-core'; -export { connectGeoSearch } from 'react-instantsearch-core'; -export { connectHierarchicalMenu } from 'react-instantsearch-core'; -export { connectHighlight } from 'react-instantsearch-core'; -export { connectHitInsights } from 'react-instantsearch-core'; -export { connectHits } from 'react-instantsearch-core'; -export { connectHitsPerPage } from 'react-instantsearch-core'; -export { connectInfiniteHits } from 'react-instantsearch-core'; -export { connectMenu } from 'react-instantsearch-core'; -export { connectNumericMenu } from 'react-instantsearch-core'; -export { connectPagination } from 'react-instantsearch-core'; -export { connectPoweredBy } from 'react-instantsearch-core'; -export { connectQueryRules } from 'react-instantsearch-core'; -export { connectRange } from 'react-instantsearch-core'; -export { connectRefinementList } from 'react-instantsearch-core'; -export { connectScrollTo } from 'react-instantsearch-core'; -export { connectSearchBox } from 'react-instantsearch-core'; -export { connectRelevantSort } from 'react-instantsearch-core'; -export { connectSortBy } from 'react-instantsearch-core'; -export { connectStateResults } from 'react-instantsearch-core'; -export { connectStats } from 'react-instantsearch-core'; -export { connectToggleRefinement } from 'react-instantsearch-core'; - -// DOM -export { default as Breadcrumb } from './widgets/Breadcrumb'; -export { default as ClearRefinements } from './widgets/ClearRefinements'; -export { default as CurrentRefinements } from './widgets/CurrentRefinements'; -export { default as HierarchicalMenu } from './widgets/HierarchicalMenu'; -export { default as Highlight } from './widgets/Highlight'; -export { default as Hits } from './widgets/Hits'; -export { default as HitsPerPage } from './widgets/HitsPerPage'; -export { default as InfiniteHits } from './widgets/InfiniteHits'; -export { default as Menu } from './widgets/Menu'; -export { default as MenuSelect } from './widgets/MenuSelect'; -export { default as NumericMenu } from './widgets/NumericMenu'; -export { default as Pagination } from './widgets/Pagination'; -export { default as Panel } from './widgets/Panel'; -export { default as PoweredBy } from './widgets/PoweredBy'; -export { default as RangeInput } from './widgets/RangeInput'; -export { default as RangeSlider } from './widgets/RangeSlider'; -export { default as RatingMenu } from './widgets/RatingMenu'; -export { default as RefinementList } from './widgets/RefinementList'; -export { default as ScrollTo } from './widgets/ScrollTo'; -export { default as SearchBox } from './widgets/SearchBox'; -export { default as Snippet } from './widgets/Snippet'; -export { default as RelevantSort } from './widgets/RelevantSort'; -export { default as SortBy } from './widgets/SortBy'; -export { default as Stats } from './widgets/Stats'; -export { default as ToggleRefinement } from './widgets/ToggleRefinement'; -export { default as VoiceSearch } from './widgets/VoiceSearch'; -export { default as QueryRuleCustomData } from './widgets/QueryRuleCustomData'; -export { default as EXPERIMENTAL_Answers } from './widgets/Answers'; - -import DynamicWidgets from './widgets/DynamicWidgets'; -/** @deprecated use DynamicWidgets */ -const ExperimentalDynamicWidgets = DynamicWidgets; -export { DynamicWidgets, ExperimentalDynamicWidgets }; - -// hooks -export { default as EXPERIMENTAL_useAnswers } from './hooks/useAnswers'; - -// Utils -export { createClassNames } from './core/utils'; - -// voiceSearchHelper -export { default as createVoiceSearchHelper } from './lib/voiceSearchHelper'; - -// insights -export { default as getInsightsAnonymousUserToken } from './core/getInsightsAnonymousUserToken'; - -// InfiniteHits Cache -export { createInfiniteHitsSessionStorageCache } from './lib/infiniteHitsCache'; diff --git a/packages/react-instantsearch-dom/src/lib/createConcurrentSafePromise.js b/packages/react-instantsearch-dom/src/lib/createConcurrentSafePromise.js deleted file mode 100644 index 6ed07d1d49..0000000000 --- a/packages/react-instantsearch-dom/src/lib/createConcurrentSafePromise.js +++ /dev/null @@ -1,43 +0,0 @@ -// copied from -// https://github.com/algolia/autocomplete.js/blob/307a7acc4283e10a19cb7d067f04f1bea79dc56f/packages/autocomplete-core/src/utils/createConcurrentSafePromise.ts#L1:L1 -// eslint-disable-next-line valid-jsdoc -/** - * Creates a runner that executes promises in a concurrent-safe way. - * - * This is useful to prevent older promises to resolve after a newer promise, - * otherwise resulting in stale resolved values. - */ -export function createConcurrentSafePromise() { - let basePromiseId = -1; - let latestResolvedId = -1; - let latestResolvedValue = undefined; - - return function runConcurrentSafePromise(promise) { - basePromiseId++; - const currentPromiseId = basePromiseId; - - return Promise.resolve(promise).then((x) => { - // The promise might take too long to resolve and get outdated. This would - // result in resolving stale values. - // When this happens, we ignore the promise value and return the one - // coming from the latest resolved value. - // - // +----------------------------------+ - // | 100ms | - // | run(1) +---> R1 | - // | 300ms | - // | run(2) +-------------> R2 (SKIP) | - // | 200ms | - // | run(3) +--------> R3 | - // +----------------------------------+ - if (latestResolvedValue && currentPromiseId < latestResolvedId) { - return latestResolvedValue; - } - - latestResolvedId = currentPromiseId; - latestResolvedValue = x; - - return x; - }); - }; -} diff --git a/packages/react-instantsearch-dom/src/lib/debounce.ts b/packages/react-instantsearch-dom/src/lib/debounce.ts deleted file mode 100644 index 3cd2020a9b..0000000000 --- a/packages/react-instantsearch-dom/src/lib/debounce.ts +++ /dev/null @@ -1,28 +0,0 @@ -type Func = (...args: any[]) => any; - -type DebouncedFunction = ( - this: ThisParameterType, - ...args: Parameters -) => Promise>; - -// Debounce a function call to the trailing edge. -// The debounced function returns a promise. -export function debounce( - func: TFunction, - wait: number -): DebouncedFunction { - let lastTimeout: ReturnType | null = null; - return function (...args) { - // @ts-ignore-next-line - const that = this; - return new Promise((resolve, reject) => { - if (lastTimeout) { - clearTimeout(lastTimeout); - } - lastTimeout = setTimeout(() => { - lastTimeout = null; - Promise.resolve(func.apply(that, args)).then(resolve).catch(reject); - }, wait); - }); - }; -} diff --git a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/__tests__/sessionStorage.js b/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/__tests__/sessionStorage.js deleted file mode 100644 index bd67e0cd60..0000000000 --- a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/__tests__/sessionStorage.js +++ /dev/null @@ -1,101 +0,0 @@ -/** - * @jest-environment jsdom - */ - -import createInfiniteHitsSessionStorageCache from '../sessionStorage'; - -const KEY = 'ais.infiniteHits'; - -describe('createInfiniteHitsSessionStorageCache', () => { - const originalSessionStorage = window.sessionStorage; - delete window.sessionStorage; - - let store = {}; - const getItem = jest.fn((key) => store[key]); - const setItem = jest.fn((key, value) => { - store[key] = value; - }); - const removeItem = jest.fn((key) => delete store[key]); - const defaultHits = [ - { objectID: 'a', __position: 0 }, - { objectID: 'b', __position: 1 }, - { objectID: 'c', __position: 2 }, - ]; - - beforeAll(() => { - Object.defineProperty(window, 'sessionStorage', { - writable: true, - value: { - getItem, - setItem, - removeItem, - }, - }); - }); - - beforeEach(() => { - store = {}; - }); - - afterEach(() => { - getItem.mockClear(); - setItem.mockClear(); - removeItem.mockClear(); - }); - - afterAll(() => { - Object.defineProperty(window, 'sessionStorage', { - value: originalSessionStorage, - }); - }); - - it('returns null initially', () => { - const cache = createInfiniteHitsSessionStorageCache(); - expect(cache.read({ state: {} })).toBeNull(); - }); - - it('returns what it was assigned before', () => { - const cache = createInfiniteHitsSessionStorageCache(); - const state = { query: 'hello' }; - const hits = { - 1: defaultHits, - }; - cache.write({ state, hits }); - expect(cache.read({ state })).toEqual(hits); - }); - - it('returns null if the state is different', () => { - const cache = createInfiniteHitsSessionStorageCache(); - const state = { query: 'hello' }; - const newState = { query: 'world' }; - const hits = { 1: defaultHits }; - cache.write({ state, hits }); - expect(cache.read({ state: newState })).toBeNull(); - }); - - it('clears cache if fails to read', () => { - getItem.mockImplementation(() => '{invalid_json}'); - const cache = createInfiniteHitsSessionStorageCache(); - cache.read({ state: {} }); - expect(removeItem).toHaveBeenCalledTimes(1); - expect(removeItem).toHaveBeenCalledWith(KEY); - }); - - it('returns null if sessionStorage.getItem() throws', () => { - getItem.mockImplementation(() => { - throw new Error(); - }); - const cache = createInfiniteHitsSessionStorageCache(); - expect(cache.read({ state: {} })).toBeNull(); - }); - - it('does nothing if sessionStorage.setItem() throws', () => { - setItem.mockImplementation(() => { - throw new Error(); - }); - const cache = createInfiniteHitsSessionStorageCache(); - expect(() => { - cache.write({ state: {}, hits: [] }); - }).not.toThrow(); - }); -}); diff --git a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/index.js b/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/index.js deleted file mode 100644 index 6fd47d4f82..0000000000 --- a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as createInfiniteHitsSessionStorageCache } from './sessionStorage'; diff --git a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/sessionStorage.js b/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/sessionStorage.js deleted file mode 100644 index d07cc63e53..0000000000 --- a/packages/react-instantsearch-dom/src/lib/infiniteHitsCache/sessionStorage.js +++ /dev/null @@ -1,56 +0,0 @@ -import isEqual from 'react-fast-compare'; - -function getStateWithoutPage(state) { - const { page, ...rest } = state || {}; - return rest; -} - -const KEY = 'ais.infiniteHits'; - -function hasSessionStorage() { - return ( - typeof window !== 'undefined' && - typeof window.sessionStorage !== 'undefined' - ); -} - -export default function createInfiniteHitsSessionStorageCache() { - return { - read({ state }) { - if (!hasSessionStorage()) { - return null; - } - try { - const cache = JSON.parse(window.sessionStorage.getItem(KEY)); - return cache && isEqual(cache.state, getStateWithoutPage(state)) - ? cache.hits - : null; - } catch (error) { - if (error instanceof SyntaxError) { - try { - window.sessionStorage.removeItem(KEY); - } catch (err) { - // do nothing - } - } - return null; - } - }, - write({ state, hits }) { - if (!hasSessionStorage()) { - return; - } - try { - window.sessionStorage.setItem( - KEY, - JSON.stringify({ - state: getStateWithoutPage(state), - hits, - }) - ); - } catch (error) { - // do nothing - } - }, - }; -} diff --git a/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/__tests__/index.ts b/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/__tests__/index.ts deleted file mode 100644 index bda056ac92..0000000000 --- a/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/__tests__/index.ts +++ /dev/null @@ -1,218 +0,0 @@ -/** - * @jest-environment jsdom - */ - -// copied from https://github.com/algolia/instantsearch.js/blob/688e36a67bb4c63d008d8abc02257a7b7c04e513/src/lib/voiceSearchHelper/__tests__/index-test.ts - -import createVoiceSearchHelper from '..'; - -type DummySpeechRecognition = () => void; -declare global { - interface Window { - webkitSpeechRecognition?: SpeechRecognition | DummySpeechRecognition; - SpeechRecognition?: SpeechRecognition | DummySpeechRecognition; - } -} - -const start = jest.fn(); -const stop = jest.fn(); - -const createFakeSpeechRecognition = (): jest.Mock => { - const simulateListener: any = {}; - const mock = jest.fn().mockImplementation(() => ({ - start, - stop, - addEventListener(eventName: string, callback: () => void) { - simulateListener[eventName] = callback; - }, - removeEventListener() {}, - })); - (mock as any).simulateListener = simulateListener; - return mock; -}; - -describe('VoiceSearchHelper', () => { - afterEach(() => { - // @ts-expect-error - delete window.webkitSpeechRecognition; - // @ts-expect-error - delete window.SpeechRecognition; - }); - - it('has initial state correctly', () => { - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - expect(voiceSearchHelper.getState()).toEqual({ - errorCode: undefined, - isSpeechFinal: false, - status: 'initial', - transcript: '', - }); - }); - - it('is not supported', () => { - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - expect(voiceSearchHelper.isBrowserSupported()).toBe(false); - }); - - it('is not listening', () => { - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - expect(voiceSearchHelper.isListening()).toBe(false); - }); - - it('is supported with webkitSpeechRecognition', () => { - // @ts-expect-error - window.webkitSpeechRecognition = () => {}; - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - expect(voiceSearchHelper.isBrowserSupported()).toBe(true); - }); - - it('is supported with SpeechRecognition', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - expect(voiceSearchHelper.isBrowserSupported()).toBe(true); - }); - - it('works with mock SpeechRecognition (searchAsYouSpeak:false)', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const { simulateListener } = window.SpeechRecognition as any; - const onQueryChange = jest.fn(); - const onStateChange = jest.fn(); - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange, - onStateChange, - }); - - voiceSearchHelper.toggleListening(); - expect(onStateChange).toHaveBeenCalledTimes(1); - expect(voiceSearchHelper.getState().status).toEqual('askingPermission'); - simulateListener.start(); - expect(voiceSearchHelper.getState().status).toEqual('waiting'); - simulateListener.result({ - results: [ - (() => { - const obj = [ - { - transcript: 'Hello World', - }, - ]; - (obj as any).isFinal = true; - return obj; - })(), - ], - }); - expect(voiceSearchHelper.getState().status).toEqual('recognizing'); - expect(voiceSearchHelper.getState().transcript).toEqual('Hello World'); - expect(voiceSearchHelper.getState().isSpeechFinal).toBe(true); - expect(onQueryChange).toHaveBeenCalledTimes(0); - simulateListener.end(); - expect(onQueryChange).toHaveBeenCalledWith('Hello World'); - expect(voiceSearchHelper.getState().status).toEqual('finished'); - }); - - it('works with mock SpeechRecognition (searchAsYouSpeak:true)', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const { simulateListener } = window.SpeechRecognition as any; - const onQueryChange = jest.fn(); - const onStateChange = jest.fn(); - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: true, - onQueryChange, - onStateChange, - }); - - voiceSearchHelper.toggleListening(); - expect(onStateChange).toHaveBeenCalledTimes(1); - expect(voiceSearchHelper.getState().status).toEqual('askingPermission'); - simulateListener.start(); - expect(voiceSearchHelper.getState().status).toEqual('waiting'); - simulateListener.result({ - results: [ - (() => { - const obj = [ - { - transcript: 'Hello World', - }, - ]; - (obj as any).isFinal = true; - return obj; - })(), - ], - }); - expect(voiceSearchHelper.getState().status).toEqual('recognizing'); - expect(voiceSearchHelper.getState().transcript).toEqual('Hello World'); - expect(voiceSearchHelper.getState().isSpeechFinal).toBe(true); - expect(onQueryChange).toHaveBeenCalledWith('Hello World'); - simulateListener.end(); - expect(onQueryChange).toHaveBeenCalledTimes(1); - expect(voiceSearchHelper.getState().status).toEqual('finished'); - }); - - it('works with onerror', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const { simulateListener } = window.SpeechRecognition as any; - const onQueryChange = jest.fn(); - const onStateChange = jest.fn(); - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: true, - onQueryChange, - onStateChange, - }); - voiceSearchHelper.toggleListening(); - expect(voiceSearchHelper.getState().status).toEqual('askingPermission'); - simulateListener.error({ - error: 'not-allowed', - }); - expect(voiceSearchHelper.getState().status).toEqual('error'); - expect(voiceSearchHelper.getState().errorCode).toEqual('not-allowed'); - simulateListener.end(); - expect(onQueryChange).toHaveBeenCalledTimes(0); - }); - - it('stops listening on `dispose`', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: false, - onQueryChange: () => {}, - onStateChange: () => {}, - }); - voiceSearchHelper.toggleListening(); - voiceSearchHelper.dispose(); - expect(stop).toHaveBeenCalledTimes(1); - }); - - it('stops and the status becomes `finished`', () => { - window.SpeechRecognition = createFakeSpeechRecognition(); - const onQueryChange = (): void => {}; - const onStateChange = (): void => {}; - const voiceSearchHelper = createVoiceSearchHelper({ - searchAsYouSpeak: true, - onQueryChange, - onStateChange, - }); - - voiceSearchHelper.toggleListening(); - voiceSearchHelper.toggleListening(); - expect(voiceSearchHelper.getState().status).toBe('finished'); - }); -}); diff --git a/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/index.ts b/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/index.ts deleted file mode 100644 index a682921ccd..0000000000 --- a/packages/react-instantsearch-dom/src/lib/voiceSearchHelper/index.ts +++ /dev/null @@ -1,181 +0,0 @@ -// copied from https://github.com/algolia/instantsearch.js/blob/688e36a67bb4c63d008d8abc02257a7b7c04e513/src/lib/voiceSearchHelper/index.ts - -// #region wrong SpeechRecognition-related types -// This is not released in typescript yet, so we're copy&pasting the type definition from -// https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/924 -export type SpeechRecognitionErrorCode = - | 'aborted' - | 'audio-capture' - | 'bad-grammar' - | 'language-not-supported' - | 'network' - | 'no-speech' - | 'not-allowed' - | 'service-not-allowed'; - -interface SpeechRecognitionErrorEvent extends Event { - readonly error: SpeechRecognitionErrorCode; - readonly message: string; -} -// #endregion wrong SpeechRecognition-related types - -export type VoiceSearchHelperParams = { - searchAsYouSpeak: boolean; - language?: string; - onQueryChange: (query: string) => void; - onStateChange: () => void; -}; - -export type Status = - | 'initial' - | 'askingPermission' - | 'waiting' - | 'recognizing' - | 'finished' - | 'error'; - -export type VoiceListeningState = { - status: Status; - transcript: string; - isSpeechFinal: boolean; - errorCode?: SpeechRecognitionErrorCode; -}; - -export type VoiceSearchHelper = { - getState: () => VoiceListeningState; - isBrowserSupported: () => boolean; - isListening: () => boolean; - toggleListening: () => void; - dispose: () => void; -}; - -export type ToggleListening = () => void; - -export default function createVoiceSearchHelper({ - searchAsYouSpeak, - language, - onQueryChange, - onStateChange, -}: VoiceSearchHelperParams): VoiceSearchHelper { - const SpeechRecognitionAPI: new () => SpeechRecognition = - (window as any).webkitSpeechRecognition || - (window as any).SpeechRecognition; - const getDefaultState = (status: Status): VoiceListeningState => ({ - status, - transcript: '', - isSpeechFinal: false, - errorCode: undefined, - }); - let state: VoiceListeningState = getDefaultState('initial'); - let recognition: SpeechRecognition | undefined; - - const isBrowserSupported = (): boolean => Boolean(SpeechRecognitionAPI); - - const isListening = (): boolean => - state.status === 'askingPermission' || - state.status === 'waiting' || - state.status === 'recognizing'; - - const setState = (newState: Partial = {}): void => { - state = { ...state, ...newState }; - onStateChange(); - }; - - const getState = (): VoiceListeningState => state; - - const resetState = (status: Status = 'initial'): void => { - setState(getDefaultState(status)); - }; - - const onStart = (): void => { - setState({ - status: 'waiting', - }); - }; - - const onError = (event: SpeechRecognitionErrorEvent): void => { - setState({ status: 'error', errorCode: event.error }); - }; - - const onResult = (event: SpeechRecognitionEvent): void => { - setState({ - status: 'recognizing', - transcript: - (event.results[0] && - event.results[0][0] && - event.results[0][0].transcript) || - '', - isSpeechFinal: event.results[0] && event.results[0].isFinal, - }); - if (searchAsYouSpeak && state.transcript) { - onQueryChange(state.transcript); - } - }; - - const onEnd = (): void => { - if (!state.errorCode && state.transcript && !searchAsYouSpeak) { - onQueryChange(state.transcript); - } - if (state.status !== 'error') { - setState({ status: 'finished' }); - } - }; - - const start = (): void => { - recognition = new SpeechRecognitionAPI(); - if (!recognition) { - return; - } - resetState('askingPermission'); - recognition.interimResults = true; - if (language) { - recognition.lang = language; - } - recognition.addEventListener('start', onStart); - // @ts-ignore: refer to the top `wrong SpeechRecognition-related types` comments - recognition.addEventListener('error', onError); - recognition.addEventListener('result', onResult); - recognition.addEventListener('end', onEnd); - recognition.start(); - }; - - const dispose = (): void => { - if (!recognition) { - return; - } - recognition.stop(); - recognition.removeEventListener('start', onStart); - // @ts-ignore: refer to the top `wrong SpeechRecognition-related types` comments - recognition.removeEventListener('error', onError); - recognition.removeEventListener('result', onResult); - recognition.removeEventListener('end', onEnd); - recognition = undefined; - }; - - const stop = (): void => { - dispose(); - // Because `dispose` removes event listeners, `end` listener is not called. - // So we're setting the `status` as `finished` here. - // If we don't do it, it will be still `waiting` or `recognizing`. - resetState('finished'); - }; - - const toggleListening = (): void => { - if (!isBrowserSupported()) { - return; - } - if (isListening()) { - stop(); - } else { - start(); - } - }; - - return { - getState, - isBrowserSupported, - isListening, - toggleListening, - dispose, - }; -} diff --git a/packages/react-instantsearch-dom/src/server.js b/packages/react-instantsearch-dom/src/server.js deleted file mode 100644 index 3b03381188..0000000000 --- a/packages/react-instantsearch-dom/src/server.js +++ /dev/null @@ -1 +0,0 @@ -export { findResultsState } from './core/createInstantSearchServer'; diff --git a/packages/react-instantsearch-dom/src/widgets/Answers.js b/packages/react-instantsearch-dom/src/widgets/Answers.js deleted file mode 100644 index 03e9884acf..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/Answers.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; - -import { createClassNames } from '../core/utils'; -import useAnswers from '../hooks/useAnswers'; - -const cx = createClassNames('Answers'); - -/* eslint-disable react/prop-types */ -function DefaultAnswersComponent({ isLoading, hits }) { - return ( -
    -
    - {isLoading ? ( -
    - ) : ( -
      - {hits.map((hit, index) => ( -
    • - {JSON.stringify(hit)} -
    • - ))} -
    - )} -
    - ); -} - -export default function Answers({ - searchClient, - queryLanguages, - attributesForPrediction, - nbHits = 1, - renderDebounceTime, - searchDebounceTime, - answersComponent: AnswersComponent = DefaultAnswersComponent, - ...extraParameters -}) { - const { hits, isLoading } = useAnswers({ - searchClient, - queryLanguages, - attributesForPrediction, - nbHits, - renderDebounceTime, - searchDebounceTime, - ...extraParameters, - }); - - return ; -} -/* eslint-enable react/prop-types */ diff --git a/packages/react-instantsearch-dom/src/widgets/Breadcrumb.js b/packages/react-instantsearch-dom/src/widgets/Breadcrumb.js deleted file mode 100644 index 5c736ede7f..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/Breadcrumb.js +++ /dev/null @@ -1,103 +0,0 @@ -import React from 'react'; -import { connectBreadcrumb } from 'react-instantsearch-core'; - -import Breadcrumb from '../components/Breadcrumb'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * A breadcrumb is a secondary navigation scheme that allows the user to see where the current page - * is in relation to the website or web application’s hierarchy. - * In terms of usability, using a breadcrumb reduces the number of actions a visitor needs to take in - * order to get to a higher-level page. - * - * If you want to select a specific refinement for your Breadcrumb component, you will need to - * use a [Virtual Hierarchical Menu](https://community.algolia.com/react-instantsearch/guide/Virtual_widgets.html) - * and set its defaultRefinement that will be then used by the Breadcrumb. - * - * @name Breadcrumb - * @kind widget - * @requirements Breadcrumbs are used for websites with a large amount of content organised in a hierarchical manner. - * The typical example is an e-commerce website which has a large variety of products grouped into logical categories - * (with categories, subcategories which also have subcategories).To use this widget, your attributes must be formatted in a specific way. - * - * Keep in mind that breadcrumbs shouldn’t replace effective primary navigation menus: - * it is only an alternative way to navigate around the website. - * - * If, for instance, you would like to have a breadcrumb of categories, objects in your index - * should be formatted this way: - * - * ```json - * { - * "categories.lvl0": "products", - * "categories.lvl1": "products > fruits", - * "categories.lvl2": "products > fruits > citrus" - * } - * ``` - * - * It's also possible to provide more than one path for each level: - * - * ```json - * { - * "categories.lvl0": ["products", "goods"], - * "categories.lvl1": ["products > fruits", "goods > to eat"] - * } - * ``` - * - * All attributes passed to the `attributes` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * - * @propType {array.} attributes - List of attributes to use to generate the hierarchy of the menu. See the example for the convention to follow - * @propType {node} [separator='>'] - Symbol used for separating hyperlinks - * @propType {string} [rootURL=null] - The originating page (homepage) - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return - * @themeKey ais-Breadcrumb - the root div of the widget - * @themeKey ais-Breadcrumb--noRefinement - the root div of the widget when there is no refinement - * @themeKey ais-Breadcrumb-list - the list of all breadcrumb items - * @themeKey ais-Breadcrumb-item - the breadcrumb navigation item - * @themeKey ais-Breadcrumb-item--selected - the selected breadcrumb item - * @themeKey ais-Breadcrumb-separator - the separator of each breadcrumb item - * @themeKey ais-Breadcrumb-link - the clickable breadcrumb element - * @translationKey rootLabel - The root's label. Accepts a string - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { Breadcrumb, InstantSearch, HierarchicalMenu } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ - -const BreadcrumbWidget = (props) => ( - - - -); - -export default connectBreadcrumb(BreadcrumbWidget, { - $$widgetType: 'ais.breadcrumb', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/ClearRefinements.js b/packages/react-instantsearch-dom/src/widgets/ClearRefinements.js deleted file mode 100644 index ba427c1567..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/ClearRefinements.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from 'react'; -import { connectCurrentRefinements } from 'react-instantsearch-core'; - -import ClearRefinements from '../components/ClearRefinements'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * The ClearRefinements widget displays a button that lets the user clean every refinement applied - * to the search. - * @name ClearRefinements - * @kind widget - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @propType {boolean} [clearsQuery=false] - Pass true to also clear the search query - * @themeKey ais-ClearRefinements - the root div of the widget - * @themeKey ais-ClearRefinements-button - the clickable button - * @themeKey ais-ClearRefinements-button--disabled - the disabled clickable button - * @translationKey reset - the clear all button value - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, ClearRefinements, RefinementList } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * const App = () => ( - * - * - * - * - * ); - */ - -const ClearRefinementsWidget = (props) => ( - - - -); - -export default connectCurrentRefinements(ClearRefinementsWidget, { - $$widgetType: 'ais.clearRefinements', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/CurrentRefinements.js b/packages/react-instantsearch-dom/src/widgets/CurrentRefinements.js deleted file mode 100644 index 09411f3829..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/CurrentRefinements.js +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react'; -import { connectCurrentRefinements } from 'react-instantsearch-core'; - -import CurrentRefinements from '../components/CurrentRefinements'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * The CurrentRefinements widget displays the list of currently applied filters. - * - * It allows the user to selectively remove them. - * @name CurrentRefinements - * @kind widget - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @themeKey ais-CurrentRefinements - the root div of the widget - * @themeKey ais-CurrentRefinements--noRefinement - the root div of the widget when there is no refinement - * @themeKey ais-CurrentRefinements-list - the list of all refined items - * @themeKey ais-CurrentRefinements-list--noRefinement - the list of all refined items when there is no refinement - * @themeKey ais-CurrentRefinements-item - the refined list item - * @themeKey ais-CurrentRefinements-button - the button of each refined list item - * @themeKey ais-CurrentRefinements-label - the refined list label - * @themeKey ais-CurrentRefinements-category - the category of each item - * @themeKey ais-CurrentRefinements-categoryLabel - the label of each catgory - * @themeKey ais-CurrentRefinements-delete - the delete button of each label - * @translationKey clearFilter - the remove filter button label - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, CurrentRefinements, RefinementList } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ - -const CurrentRefinementsWidget = (props) => ( - - - -); - -export default connectCurrentRefinements(CurrentRefinementsWidget, { - $$widgetType: 'ais.currentRefinements', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/DynamicWidgets.js b/packages/react-instantsearch-dom/src/widgets/DynamicWidgets.js deleted file mode 100644 index 89eac2eadd..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/DynamicWidgets.js +++ /dev/null @@ -1,16 +0,0 @@ -/* eslint-disable react/prop-types */ -import classNames from 'classnames'; -import React from 'react'; -import { DynamicWidgets as CoreDynamicWidgets } from 'react-instantsearch-core'; - -import { createClassNames } from '../core/utils'; - -const cx = createClassNames('DynamicWidgets'); - -export default function DynamicWidgets({ children, className, ...props }) { - return ( -
    - {children} -
    - ); -} diff --git a/packages/react-instantsearch-dom/src/widgets/HierarchicalMenu.js b/packages/react-instantsearch-dom/src/widgets/HierarchicalMenu.js deleted file mode 100644 index 81d067095e..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/HierarchicalMenu.js +++ /dev/null @@ -1,106 +0,0 @@ -import React from 'react'; -import { connectHierarchicalMenu } from 'react-instantsearch-core'; - -import HierarchicalMenu from '../components/HierarchicalMenu'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * The hierarchical menu lets the user browse attributes using a tree-like structure. - * - * This is commonly used for multi-level categorization of products on e-commerce - * websites. From a UX point of view, we suggest not displaying more than two levels deep. - * - * @name HierarchicalMenu - * @kind widget - * @requirements To use this widget, your attributes must be formatted in a specific way. - * If you want for example to have a hierarchical menu of categories, objects in your index - * should be formatted this way: - * - * ```json - * [{ - * "objectID": "321432", - * "name": "lemon", - * "categories.lvl0": "products", - * "categories.lvl1": "products > fruits", - * }, - * { - * "objectID": "8976987", - * "name": "orange", - * "categories.lvl0": "products", - * "categories.lvl1": "products > fruits", - * }] - * ``` - * - * It's also possible to provide more than one path for each level: - * - * ```json - * { - * "objectID": "321432", - * "name": "lemon", - * "categories.lvl0": ["products", "goods"], - * "categories.lvl1": ["products > fruits", "goods > to eat"] - * } - * ``` - * - * All attributes passed to the `attributes` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * - * @propType {array.} attributes - List of attributes to use to generate the hierarchy of the menu. See the example for the convention to follow. - * @propType {boolean} [showMore=false] - Flag to activate the show more button, for toggling the number of items between limit and showMoreLimit. - * @propType {number} [limit=10] - The maximum number of items displayed. - * @propType {number} [showMoreLimit=20] - The maximum number of items displayed when the user triggers the show more. Not considered if `showMore` is false. - * @propType {string} [separator='>'] - Specifies the level separator used in the data. - * @propType {string} [rootPath=null] - The path to use if the first level is not the root level. - * @propType {boolean} [showParentLevel=true] - Flag to set if the parent level should be displayed. - * @propType {string} [defaultRefinement] - the item value selected by default - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @themeKey ais-HierarchicalMenu - the root div of the widget - * @themeKey ais-HierarchicalMenu-noRefinement - the root div of the widget when there is no refinement - * @themeKey ais-HierarchicalMenu-searchBox - the search box of the widget. See [the SearchBox documentation](widgets/SearchBox.html#classnames) for the classnames and translation keys of the SearchBox. - * @themeKey ais-HierarchicalMenu-list - the list of menu items - * @themeKey ais-HierarchicalMenu-list--child - the child list of menu items - * @themeKey ais-HierarchicalMenu-item - the menu list item - * @themeKey ais-HierarchicalMenu-item--selected - the selected menu list item - * @themeKey ais-HierarchicalMenu-item--parent - the menu list item containing children - * @themeKey ais-HierarchicalMenu-link - the clickable menu element - * @themeKey ais-HierarchicalMenu-link--selected - the clickable element of a selected menu list item - * @themeKey ais-HierarchicalMenu-label - the label of each item - * @themeKey ais-HierarchicalMenu-count - the count of values for each item - * @themeKey ais-HierarchicalMenu-showMore - the button used to display more categories - * @themeKey ais-HierarchicalMenu-showMore--disabled - the disabled button used to display more categories - * @translationKey showMore - The label of the show more button. Accepts one parameter, a boolean that is true if the values are expanded - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, HierarchicalMenu } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * ); - */ - -const HierarchicalMenuWidget = (props) => ( - - - -); - -export default connectHierarchicalMenu(HierarchicalMenuWidget, { - $$widgetType: 'ais.hierarchicalMenu', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/Highlight.js b/packages/react-instantsearch-dom/src/widgets/Highlight.js deleted file mode 100644 index 066e9f9c9d..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/Highlight.js +++ /dev/null @@ -1,46 +0,0 @@ -import { connectHighlight } from 'react-instantsearch-core'; - -import Highlight from '../components/Highlight'; - -/** - * Renders any attribute from a hit into its highlighted form when relevant. - * - * Read more about it in the [Highlighting results](guide/Highlighting_results.html) guide. - * @name Highlight - * @kind widget - * @propType {string} attribute - location of the highlighted attribute in the hit (the corresponding element can be either a string or an array of strings) - * @propType {object} hit - hit object containing the highlighted attribute - * @propType {string} [tagName='em'] - tag to be used for highlighted parts of the hit - * @propType {string} [nonHighlightedTagName='span'] - tag to be used for the parts of the hit that are not highlighted - * @propType {node} [separator=','] - symbol used to separate the elements of the array in case the attribute points to an array of strings. - * @themeKey ais-Highlight - root of the component - * @themeKey ais-Highlight-highlighted - part of the text which is highlighted - * @themeKey ais-Highlight-nonHighlighted - part of the text that is not highlighted - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, SearchBox, Hits, Highlight } from 'react-instantsearch-dom'; - * - * const Hit = ({ hit }) => ( - *
    - * - *
    - * ); - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ - -export default connectHighlight(Highlight, { $$widgetType: 'ais.highlight' }); diff --git a/packages/react-instantsearch-dom/src/widgets/Hits.js b/packages/react-instantsearch-dom/src/widgets/Hits.js deleted file mode 100644 index e5b202ed76..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/Hits.js +++ /dev/null @@ -1,38 +0,0 @@ -import { connectHits } from 'react-instantsearch-core'; - -import Hits from '../components/Hits'; - -/** - * Displays a list of hits. - * - * To configure the number of hits being shown, use the [HitsPerPage widget](widgets/HitsPerPage.html), - * [connectHitsPerPage connector](connectors/connectHitsPerPage.html) or the [Configure widget](widgets/Configure.html). - * - * @name Hits - * @kind widget - * @propType {Component} [hitComponent] - Component used for rendering each hit from - * the results. If it is not provided the rendering defaults to displaying the - * hit in its JSON form. The component will be called with a `hit` prop. - * @themeKey ais-Hits - the root div of the widget - * @themeKey ais-Hits-list - the list of results - * @themeKey ais-Hits-item - the hit list item - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, Hits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * const App = () => ( - * - * - * - * ); - */ - -export default connectHits(Hits, { $$widgetType: 'ais.hits' }); diff --git a/packages/react-instantsearch-dom/src/widgets/HitsPerPage.js b/packages/react-instantsearch-dom/src/widgets/HitsPerPage.js deleted file mode 100644 index 464cc1e35b..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/HitsPerPage.js +++ /dev/null @@ -1,50 +0,0 @@ -import { connectHitsPerPage } from 'react-instantsearch-core'; - -import HitsPerPage from '../components/HitsPerPage'; - -/** - * The HitsPerPage widget displays a dropdown menu to let the user change the number - * of displayed hits. - * - * If you only want to configure the number of hits per page without - * displaying a widget, you should use the `` widget. See [`` documentation](widgets/Configure.html) - * - * @name HitsPerPage - * @kind widget - * @propType {string} id - The id of the select input - * @propType {{value: number, label: string}[]} items - List of available options. - * @propType {number} defaultRefinement - The number of items selected by default - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @themeKey ais-HitsPerPage - the root div of the widget - * @themeKey ais-HitsPerPage-select - the select - * @themeKey ais-HitsPerPage-option - the select option - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, HitsPerPage, Hits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * - * ); - */ - -export default connectHitsPerPage(HitsPerPage, { - $$widgetType: 'ais.hitsPerPage', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/InfiniteHits.js b/packages/react-instantsearch-dom/src/widgets/InfiniteHits.js deleted file mode 100644 index 7cc9d03816..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/InfiniteHits.js +++ /dev/null @@ -1,44 +0,0 @@ -import { connectInfiniteHits } from 'react-instantsearch-core'; - -import InfiniteHits from '../components/InfiniteHits'; - -/** - * Displays an infinite list of hits along with a **load more** button. - * - * To configure the number of hits being shown, use the [HitsPerPage widget](widgets/HitsPerPage.html), - * [connectHitsPerPage connector](connectors/connectHitsPerPage.html) or the [Configure widget](widgets/Configure.html). - * - * @name InfiniteHits - * @kind widget - * @propType {Component} [hitComponent] - Component used for rendering each hit from - * the results. If it is not provided the rendering defaults to displaying the - * hit in its JSON form. The component will be called with a `hit` prop. - * @themeKey ais-InfiniteHits - the root div of the widget - * @themeKey ais-InfiniteHits-list - the list of hits - * @themeKey ais-InfiniteHits-item - the hit list item - * @themeKey ais-InfiniteHits-loadMore - the button used to display more results - * @themeKey ais-InfiniteHits-loadMore--disabled - the disabled button used to display more results - * @translationKey loadMore - the label of load more button - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, InfiniteHits } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * ); - */ - -export default connectInfiniteHits(InfiniteHits, { - $$widgetType: 'ais.infiniteHits', -}); diff --git a/packages/react-instantsearch-dom/src/widgets/Menu.js b/packages/react-instantsearch-dom/src/widgets/Menu.js deleted file mode 100644 index c6780c5797..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/Menu.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import { connectMenu } from 'react-instantsearch-core'; - -import Menu from '../components/Menu'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * The Menu component displays a menu that lets the user choose a single value for a specific attribute. - * @name Menu - * @kind widget - * @requirements The attribute passed to the `attribute` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * - * If you are using the `searchable` prop, you'll also need to make the attribute 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). - * @propType {string} attribute - the name of the attribute in the record - * @propType {boolean} [showMore=false] - true if the component should display a button that will expand the number of items - * @propType {number} [limit=10] - the minimum number of diplayed items - * @propType {number} [showMoreLimit=20] - the maximun number of displayed items. Only used when showMore is set to `true` - * @propType {string} [defaultRefinement] - the value of the item selected by default - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @propType {boolean} [searchable=false] - true if the component should display an input to search for 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/). - * @themeKey ais-Menu - the root div of the widget - * @themeKey ais-Menu-searchBox - the search box of the widget. See [the SearchBox documentation](widgets/SearchBox.html#classnames) for the classnames and translation keys of the SearchBox. - * @themeKey ais-Menu-list - the list of all menu items - * @themeKey ais-Menu-item - the menu list item - * @themeKey ais-Menu-item--selected - the selected menu list item - * @themeKey ais-Menu-link - the clickable menu element - * @themeKey ais-Menu-label - the label of each item - * @themeKey ais-Menu-count - the count of values for each item - * @themeKey ais-Menu-noResults - the div displayed when there are no results - * @themeKey ais-Menu-showMore - the button used to display more categories - * @themeKey ais-Menu-showMore--disabled - the disabled button used to display more categories - * @translationkey showMore - The label of the show more button. Accepts one parameters, a boolean that is true if the values are expanded - * @translationkey noResults - The label of the no results text when no search for facet values results are found. - * @example - * import React from 'react'; - * import algoliasearch from 'algoliasearch/lite'; - * import { InstantSearch, Menu } from 'react-instantsearch-dom'; - * - * const searchClient = algoliasearch( - * 'latency', - * '6be0576ff61c053d5f9a3225e2a90f76' - * ); - * - * const App = () => ( - * - * - * - * ); - */ - -const MenuWidget = (props) => ( - - - -); - -export default connectMenu(MenuWidget, { $$widgetType: 'ais.menu' }); diff --git a/packages/react-instantsearch-dom/src/widgets/MenuSelect.js b/packages/react-instantsearch-dom/src/widgets/MenuSelect.js deleted file mode 100644 index 7089f12f75..0000000000 --- a/packages/react-instantsearch-dom/src/widgets/MenuSelect.js +++ /dev/null @@ -1,52 +0,0 @@ -import React from 'react'; -import { connectMenu } from 'react-instantsearch-core'; - -import MenuSelect from '../components/MenuSelect'; -import PanelCallbackHandler from '../components/PanelCallbackHandler'; - -/** - * The MenuSelect component displays a select that lets the user choose a single value for a specific attribute. - * @name MenuSelect - * @kind widget - * @requirements The attribute passed to the `attribute` prop must be present in "attributes for faceting" - * on the Algolia dashboard or configured as `attributesForFaceting` via a set settings call to the Algolia API. - * @propType {string} id - the id of the select input - * @propType {string} attribute - the name of the attribute in the record - * @propType {string} [defaultRefinement] - the value of the item selected by default - * @propType {number} [limit=10] - the minimum number of diplayed items - * @propType {function} [transformItems] - Function to modify the items being displayed, e.g. for filtering or sorting them. Takes an items as parameter and expects it back in return. - * @themeKey ais-MenuSelect - the root div of the widget - * @themeKey ais-MenuSelect-noRefinement - the root div of the widget when there is no refinement - * @themeKey ais-MenuSelect-select - the ` - {eventName} - - ))} - -
    - - (Click on the action logger tab of the right sidebar to see event - logs) - -
    -
    - - - - ); - } -} - -stories.add('with event listeners', () => ); diff --git a/packages/react-instantsearch-dom/stories/Snippet.stories.js b/packages/react-instantsearch-dom/stories/Snippet.stories.js deleted file mode 100644 index 0a5720d20f..0000000000 --- a/packages/react-instantsearch-dom/stories/Snippet.stories.js +++ /dev/null @@ -1,61 +0,0 @@ -import { text } from '@storybook/addon-knobs'; -import { storiesOf } from '@storybook/react'; -import PropTypes from 'prop-types'; -import React from 'react'; -import { Snippet, Hits, Configure } from 'react-instantsearch-dom'; - -import { WrapWithHits } from './util'; - -const stories = storiesOf('Snippet', module); - -const Default = ({ hit }) => ( -
    -

    - -

    -

    - -

    -
    -); - -Default.propTypes = { - hit: PropTypes.object.isRequired, -}; - -const StrongHits = ({ hit }) => ( -
    -

    - -

    -

    - -

    -
    -); - -StrongHits.propTypes = { - hit: PropTypes.object.isRequired, -}; - -stories - .add('default', () => ( - - - - - )) - .add('playground', () => ( - - - - - )); diff --git a/packages/react-instantsearch-dom/stories/SortBy.stories.js b/packages/react-instantsearch-dom/stories/SortBy.stories.js deleted file mode 100644 index 5a429b4916..0000000000 --- a/packages/react-instantsearch-dom/stories/SortBy.stories.js +++ /dev/null @@ -1,47 +0,0 @@ -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { Panel, SortBy } from 'react-instantsearch-dom'; - -import { WrapWithHits } from './util'; - -const stories = storiesOf('SortBy', module); - -stories - .add('default', () => ( - - - - )) - .add('without label', () => ( - - - - )) - .add('with Panel', () => ( - - - - - - )); diff --git a/packages/react-instantsearch-dom/stories/Stats.stories.js b/packages/react-instantsearch-dom/stories/Stats.stories.js deleted file mode 100644 index 2aad5e665d..0000000000 --- a/packages/react-instantsearch-dom/stories/Stats.stories.js +++ /dev/null @@ -1,49 +0,0 @@ -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { Panel, Stats, RelevantSort } from 'react-instantsearch-dom'; - -import { WrapWithHits } from './util'; - -const stories = storiesOf('Stats', module); - -stories - .add('default', () => ( - -
    - -
    -
    - )) - .add('with Panel', () => ( - - - - - - )) - .add('with sorted hits', () => ( - -
    - - ( -
    - {isRelevantSorted - ? 'We removed some search results to show you the most relevant ones' - : 'Currently showing all results'} -
    - )} - buttonTextComponent={({ isRelevantSorted }) => ( -
    - {isRelevantSorted ? 'See all results' : 'See relevant results'} -
    - )} - /> -
    -
    - )); diff --git a/packages/react-instantsearch-dom/stories/ToggleRefinement.stories.js b/packages/react-instantsearch-dom/stories/ToggleRefinement.stories.js deleted file mode 100644 index c08d3441be..0000000000 --- a/packages/react-instantsearch-dom/stories/ToggleRefinement.stories.js +++ /dev/null @@ -1,39 +0,0 @@ -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { Panel, ToggleRefinement } from 'react-instantsearch-dom'; - -import { WrapWithHits } from './util'; - -const stories = storiesOf('ToggleRefinement', module); - -stories - .add('default', () => ( - - - - )) - .add('checked by default', () => ( - - - - )) - .add('with Panel', () => ( - - - - - - )); diff --git a/packages/react-instantsearch-dom/stories/VoiceSearch.stories.tsx b/packages/react-instantsearch-dom/stories/VoiceSearch.stories.tsx deleted file mode 100644 index b453474011..0000000000 --- a/packages/react-instantsearch-dom/stories/VoiceSearch.stories.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import { storiesOf } from '@storybook/react'; -import React from 'react'; -import { VoiceSearch, SearchBox } from 'react-instantsearch-dom'; - -import { WrapWithHits } from './util'; - -import type { InnerComponentProps } from '../src/components/VoiceSearch'; - -const stories = storiesOf('VoiceSearch', module); - -stories - .add('default', () => ( - -

    - To see this button disabled, test it on unsupported browsers like - Safari, Firefox, etc. -

    - -
    - )) - .add('without status', () => ( - - null} /> - - )) - .add('with a SearchBox', () => ( - - - - - )) - .add('with a custom button text', () => ( - -
    - - isListening ? '⏹' : '🎙' - } - /> -
    -
    - )) - .add('with full status', () => { - const Status = ({ - status, - errorCode, - isListening, - transcript, - isSpeechFinal, - isBrowserSupported, - }: InnerComponentProps) => { - return ( -
    -

    status: {status}

    -

    errorCode: {errorCode}

    -

    isListening: {isListening ? 'true' : 'false'}

    -

    transcript: {transcript}

    -

    isSpeechFinal: {isSpeechFinal ? 'true' : 'false'}

    -

    isBrowserSupported: {isBrowserSupported ? 'true' : 'false'}

    -
    - ); - }; - - return ( - - - - ); - }) - .add('search as you speak', () => { - const Status = ({ - status, - errorCode, - isListening, - transcript, - isSpeechFinal, - isBrowserSupported, - }: InnerComponentProps) => { - return ( -
    -

    status: {status}

    -

    errorCode: {errorCode}

    -

    isListening: {isListening ? 'true' : 'false'}

    -

    transcript: {transcript}

    -

    isSpeechFinal: {isSpeechFinal ? 'true' : 'false'}

    -

    isBrowserSupported: {isBrowserSupported ? 'true' : 'false'}

    -
    - ); - }; - return ( - - - - ); - }) - .add('example of dynamic UI working with SearchBox', () => { - const Status = ({ isListening, transcript }: InnerComponentProps) => { - return ( -
    - {transcript} -
    - ); - }; - - return ( - -
    - - -
    -
    - ); - }) - .add('with additional paramaters', () => ( - - {}} /> - - - )) - .add('with additional paramaters & language', () => ( - - {}} /> - - )) - .add('with additional paramaters & user set & language', () => ( - - ({ analyticsTags: ['voice'] })} - /> - - )); diff --git a/packages/react-instantsearch-dom/stories/places/connector.js b/packages/react-instantsearch-dom/stories/places/connector.js deleted file mode 100644 index f0998d6929..0000000000 --- a/packages/react-instantsearch-dom/stories/places/connector.js +++ /dev/null @@ -1,29 +0,0 @@ -import { createConnector } from 'react-instantsearch-dom'; - -export default createConnector({ - displayName: 'AlgoliaGeoSearch', - - getProvidedProps() { - return {}; - }, - - refine(props, searchState, nextValue) { - return { - ...searchState, - aroundLatLng: nextValue, - boundingBox: {}, - }; - }, - - getSearchParameters(searchParameters, props, searchState) { - const currentRefinement = - searchState.aroundLatLng || props.defaultRefinement; - - return searchParameters - .setQueryParameter('insideBoundingBox') - .setQueryParameter( - 'aroundLatLng', - `${currentRefinement.lat}, ${currentRefinement.lng}` - ); - }, -}); diff --git a/packages/react-instantsearch-dom/stories/places/index.js b/packages/react-instantsearch-dom/stories/places/index.js deleted file mode 100644 index cbfa455beb..0000000000 --- a/packages/react-instantsearch-dom/stories/places/index.js +++ /dev/null @@ -1,45 +0,0 @@ -import places from 'places.js'; -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; - -import connect from './connector'; - -class Places extends Component { - static propTypes = { - refine: PropTypes.func.isRequired, - defaultRefinement: PropTypes.object.isRequired, - }; - - createRef = (c) => (this.element = c); - - componentDidMount() { - const { refine, defaultRefinement } = this.props; - - const autocomplete = places({ - container: this.element, - }); - - autocomplete.on('change', (event) => { - refine(event.suggestion.latlng); - }); - - autocomplete.on('clear', () => { - refine(defaultRefinement); - }); - } - - render() { - return ( -
    - -
    - ); - } -} - -export default connect(Places); diff --git a/packages/react-instantsearch-dom/stories/util.d.ts b/packages/react-instantsearch-dom/stories/util.d.ts deleted file mode 100644 index aff0cc4cf3..0000000000 --- a/packages/react-instantsearch-dom/stories/util.d.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { PlainSearchParameters } from 'algoliasearch-helper'; -import type React from 'react'; - -export const Content: React.FC<{ - linkedStoryGroup?: string; - hasPlayground?: boolean; - children?: React.ReactNode; - resultsView?: React.ReactNode; -}>; - -export const WrapWithHits: React.FC<{ - appId?: string; - apiKey?: string; - indexName?: string; - children?: React.ReactNode; - searchBox?: boolean; - linkedStoryGroup?: string; - hasPlayground?: boolean; - pagination?: boolean; - searchParameters?: PlainSearchParameters; - hitsElement?: element; - initialSearchState?: any; - onSearchStateChange?: (searchState: any) => any; -}>; diff --git a/packages/react-instantsearch-dom/stories/util.js b/packages/react-instantsearch-dom/stories/util.js deleted file mode 100644 index bc78bcee6e..0000000000 --- a/packages/react-instantsearch-dom/stories/util.js +++ /dev/null @@ -1,196 +0,0 @@ -import { linkTo } from '@storybook/addon-links'; -import algoliasearch from 'algoliasearch/lite'; -import PropTypes from 'prop-types'; -import React, { useState, useMemo } from 'react'; -import { - InstantSearch, - ClearRefinements, - SearchBox, - Pagination, - Highlight, - Configure, - connectHits, -} from 'react-instantsearch-dom'; -import 'instantsearch.css/themes/algolia.css'; - -const Hits = ({ hits }) => ( -
    - {hits.map((hit) => ( -
    - {hit.image && ( -
    - -
    - )} -
    -
    - - - ${hit.price} - - {hit.rating} stars -
    -
    - -
    -
    - -
    -
    -
    - ))} -
    -); - -Hits.propTypes = { - hits: PropTypes.array.isRequired, -}; - -export const CustomHits = connectHits(Hits); - -export function Content({ - hasPlayground, - linkedStoryGroup, - children, - resultsView, -}) { - const sourceCodeUrl = `https://github.com/algolia/instantsearch.js/tree/master/packages/react-instantsearch-dom/stories/${linkedStoryGroup}`; - const playgroundLink = hasPlayground ? ( - - ) : null; - - const footer = linkedStoryGroup ? ( -
    - {playgroundLink} - -
    View source code
    -
    -
    - ) : null; - - const results = resultsView ? ( -
    - {resultsView} -
    - ) : null; - - return ( -
    -
    {children}
    - {results} - {footer} -
    - ); -} - -Content.propTypes = { - linkedStoryGroup: PropTypes.string, - hasPlayground: PropTypes.bool, - children: PropTypes.node, - resultsView: PropTypes.node, -}; - -export function WrapWithHits({ - searchParameters: askedSearchParameters = {}, - children, - searchBox = true, - hasPlayground = false, - linkedStoryGroup, - pagination = true, - hitsElement, - appId, - apiKey, - indexName, - initialSearchState, - onSearchStateChange, -}) { - const searchClient = useMemo(() => { - return algoliasearch(appId, apiKey); - }, [appId, apiKey]); - - const hits = hitsElement || ; - - const searchParameters = { - hitsPerPage: 3, - ...askedSearchParameters, - }; - - const [searchState, setSearchState] = useState(initialSearchState); - - const setNextSearchState = (nextSearchState) => { - setSearchState(nextSearchState); - onSearchStateChange(nextSearchState); - }; - - return ( - - - -
    - {searchBox ? ( - - ) : null} - -
    - {hits} -
    - {pagination ? : null} -
    -
    - } - > - {children} - - - ); -} - -WrapWithHits.propTypes = { - appId: PropTypes.string, - apiKey: PropTypes.string, - indexName: PropTypes.string, - children: PropTypes.node, - searchBox: PropTypes.bool, - linkedStoryGroup: PropTypes.string, - hasPlayground: PropTypes.bool, - pagination: PropTypes.bool, - searchParameters: PropTypes.object, - hitsElement: PropTypes.element, - initialSearchState: PropTypes.object, - onSearchStateChange: PropTypes.func, -}; - -// defaultProps added so that they're displayed in the JSX addon -WrapWithHits.defaultProps = { - appId: 'latency', - apiKey: '6be0576ff61c053d5f9a3225e2a90f76', - indexName: 'instant_search', - initialSearchState: {}, - onSearchStateChange: (searchState) => searchState, -}; diff --git a/packages/react-instantsearch-hooks-server/CHANGELOG.md b/packages/react-instantsearch-hooks-server/CHANGELOG.md deleted file mode 100644 index 19b5636d1d..0000000000 --- a/packages/react-instantsearch-hooks-server/CHANGELOG.md +++ /dev/null @@ -1,2004 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.47.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.47.2...react-instantsearch-hooks-server@6.47.3) (2023-07-27) - - -### Bug Fixes - -* add a future warning when the package name changes ([#5778](https://github.com/algolia/instantsearch.js/issues/5778)) ([3d22ee4](https://github.com/algolia/instantsearch.js/commit/3d22ee45e1f03a443323a371621262f1fe45e664)) - - - - - -## [6.47.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.47.1...react-instantsearch-hooks-server@6.47.2) (2023-07-25) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.47.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.47.0...react-instantsearch-hooks-server@6.47.1) (2023-07-19) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.47.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.46.0...react-instantsearch-hooks-server@6.47.0) (2023-07-18) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.46.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.45.1...react-instantsearch-hooks-server@6.46.0) (2023-07-10) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.45.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.45.0...react-instantsearch-hooks-server@6.45.1) (2023-07-04) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -# [6.45.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.44.3...react-instantsearch-hooks-server@6.45.0) (2023-06-20) - - -### Features - -* **algoliaAgent:** track Next.js version as Algolia agent ([#5677](https://github.com/algolia/instantsearch.js/issues/5677)) ([b205ac0](https://github.com/algolia/instantsearch.js/commit/b205ac019f79699cd608d63792b8ff5a0832aa7c)) - - - - - -## [6.44.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.44.2...react-instantsearch-hooks-server@6.44.3) (2023-06-13) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.44.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.44.1...react-instantsearch-hooks-server@6.44.2) (2023-06-05) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.44.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.44.0...react-instantsearch-hooks-server@6.44.1) (2023-05-30) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.43.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.43.0...react-instantsearch-hooks-server@6.43.1) (2023-05-16) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -# [6.43.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.42.2...react-instantsearch-hooks-server@6.43.0) (2023-04-24) - - -### Bug Fixes - -* **server:** error when multiple InstantSearch instances in getServerState ([#5588](https://github.com/algolia/instantsearch.js/issues/5588)) ([0778460](https://github.com/algolia/instantsearch.js/commit/0778460dee935b929e420b362948b4962978d3a5)) - - - - - -## [6.42.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.42.1...react-instantsearch-hooks-server@6.42.2) (2023-04-11) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.42.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.42.0...react-instantsearch-hooks-server@6.42.1) (2023-03-28) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.42.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.41.0...react-instantsearch-hooks-server@6.42.0) (2023-03-21) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.41.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.40.1...react-instantsearch-hooks-server@6.41.0) (2023-03-07) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.40.1...react-instantsearch-hooks-server@6.40.2) (2023-02-28) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.40.0...react-instantsearch-hooks-server@6.40.1) (2023-02-21) - - -### Bug Fixes - -* **readme:** remove experimental warning ([#5485](https://github.com/algolia/instantsearch.js/issues/5485)) ([4409993](https://github.com/algolia/instantsearch.js/commit/44099939b5c51c94ef294b31dc91548f1530b65b)) - - - - - -## [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.39.3...react-instantsearch-hooks-server@6.40.0) (2023-02-14) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - -## [6.39.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.39.2...react-instantsearch-hooks-server@6.39.3) (2023-02-07) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.39.1...react-instantsearch-hooks-server@6.39.2) (2023-01-30) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.39.0...react-instantsearch-hooks-server@6.39.1) (2023-01-26) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.38.3...react-instantsearch-hooks-server@6.39.0) (2023-01-25) - - -### Features - -* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) - - - - - -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.38.2...react-instantsearch-hooks-server@6.38.3) (2023-01-09) - -**Note:** Version bump only for package react-instantsearch-hooks-server - - - - - -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-server@6.38.1...react-instantsearch-hooks-server@6.38.2) (2023-01-03) - -### Bug Fixes - -* **getServerState:** correctly forward asynchronous errors ([#5405](https://github.com/algolia/instantsearch/pull/5405)) ([0f0e84d6](https://github.com/algolia/instantsearch/commit/0f0e84d62c58fdbe81f6e5c823ab6d19b45ee8f3)) - - - - - -## [6.38.1](https://github.com/algolia/react-instantsearch/compare/v6.38.0...v6.38.1) (2022-11-08) - - -### Bug Fixes - -* **hooks:** avoid effect in useStableValue ([#3670](https://github.com/algolia/react-instantsearch/issues/3670)) ([d1f53ae](https://github.com/algolia/react-instantsearch/commit/d1f53ae815b75f13c18fd245e0403d57e7ae391c)) - - - -# [6.38.0](https://github.com/algolia/react-instantsearch/compare/v6.37.0...v6.38.0) (2022-10-25) - - -### Features - -* **getServerState:** allow users to inject renderToString ([#3658](https://github.com/algolia/react-instantsearch/issues/3658)) ([9c10449](https://github.com/algolia/react-instantsearch/commit/9c104497b9b32337f288d70a2582c41cafb13cd6)), closes [#3633](https://github.com/algolia/react-instantsearch/issues/3633) [#3618](https://github.com/algolia/react-instantsearch/issues/3618) [vercel/next.js#40067](https://github.com/vercel/next.js/issues/40067) - -* **PoweredBy:** update component logo ([#3661](https://github.com/algolia/react-instantsearch/issues/3661)) ([69c1b2a](https://github.com/algolia/react-instantsearch/commit/69c1b2acef64d972dfa6c6beb8967032119ad2d5)) - - - -# [6.37.0](https://github.com/algolia/react-instantsearch/compare/v6.36.0...v6.37.0) (2022-10-18) - - -### Features - -* **core:** support react 18 strict mode ([#3653](https://github.com/algolia/react-instantsearch/issues/3653)) ([9174806](https://github.com/algolia/react-instantsearch/commit/9174806a7997a45893a24d149027119f4a0709c3)) - - - -# [6.36.0](https://github.com/algolia/react-instantsearch/compare/v6.35.0...v6.36.0) (2022-10-04) - - -### Features - -* **HierarchicalMenu:** add css class for link of selected menu item ([#3646](https://github.com/algolia/react-instantsearch/issues/3646)) ([980ad70](https://github.com/algolia/react-instantsearch/commit/980ad70c75e970c35c11a10a534dbe3996d6c54c)) -* **useInstantSearch:** expose status & error ([#3645](https://github.com/algolia/react-instantsearch/issues/3645)) ([f436d31](https://github.com/algolia/react-instantsearch/commit/f436d31184f3f75b33a1fdaa19c665e77948df28)) - - - -# [6.35.0](https://github.com/algolia/react-instantsearch/compare/v6.34.0...v6.35.0) (2022-09-29) - - -### Features - -* **hooks-web:** introduce Translations API ([#3638](https://github.com/algolia/react-instantsearch/issues/3638)) ([63b506f](https://github.com/algolia/react-instantsearch/commit/63b506f9dbad284f45ac17210e17c4a2a8f099b6)) - -### Fixes -* **hooks-web:** when searchAsYouType=false, pressing the reset button searches (previously only reset the query) ([#3642](https://github.com/algolia/react-instantsearch/issues/3642)) ([f969deb](https://github.com/algolia/react-instantsearch/commit/f969deb05fd4f53aaa251ff88b52db2224ce0786)) - -# [6.34.0](https://github.com/algolia/react-instantsearch/compare/v6.33.0...v6.34.0) (2022-09-27) - - -### Features - -* **SearchBox:** expose formRef ([#3565](https://github.com/algolia/react-instantsearch/issues/3565)) ([1c2f46d](https://github.com/algolia/react-instantsearch/commit/1c2f46da2d1cf705cfd3946c52aef4ca9ec943d7)) - - - -# [6.33.0](https://github.com/algolia/react-instantsearch/compare/v6.32.1...v6.33.0) (2022-09-15) - - -### Bug Fixes - -* **react-native:** mark as compatible with react 18 ([#3614](https://github.com/algolia/react-instantsearch/issues/3614)) ([2a191a8](https://github.com/algolia/react-instantsearch/commit/2a191a84751127de5a3eb34b59b460a1d1bfe594)) -* **rish:** hide reset button when search is stalled in `SearchBox` ([#3617](https://github.com/algolia/react-instantsearch/issues/3617)) ([93ee9d0](https://github.com/algolia/react-instantsearch/commit/93ee9d0212893cef4842c86b7c78f285aa136be8)) - - -### Features - -* **dependencies:** update instantsearch and helper ([#3622](https://github.com/algolia/react-instantsearch/issues/3622)) ([6773ab1](https://github.com/algolia/react-instantsearch/commit/6773ab169cd74dfe1133e255daade4d57e99d9a4)) - - - -## [6.32.1](https://github.com/algolia/react-instantsearch/compare/v6.32.0...v6.32.1) (2022-08-26) - - -### Bug Fixes - -* **useInstantSearch:** prevent `results` from being `null` when first search is stalled ([#3597](https://github.com/algolia/react-instantsearch/issues/3597)) ([6f71d78](https://github.com/algolia/react-instantsearch/commit/6f71d78868fde55a3f9c4460edc337a1e99df4f9)) - - - -# [6.32.0](https://github.com/algolia/react-instantsearch/compare/v6.31.1...v6.32.0) (2022-08-22) - - -### Features - -* **SearchBox:** introduce `autoFocus` prop ([#3599](https://github.com/algolia/react-instantsearch/issues/3599)) ([99121b9](https://github.com/algolia/react-instantsearch/commit/99121b952fd002cb6dae52af41f08beed8f6c3e2)) - - - -## [6.31.1](https://github.com/algolia/react-instantsearch/compare/v6.31.0...v6.31.1) (2022-08-08) - - -### Bug Fixes - -* **hooks:** prevent widget cleanup on `` unmount ([#3590](https://github.com/algolia/react-instantsearch/issues/3590)) ([d94899d](https://github.com/algolia/react-instantsearch/commit/d94899d1264134f0cb1ca2d266a660f1fb2a588c)) - - - -# [6.31.0](https://github.com/algolia/react-instantsearch/compare/v6.30.3...v6.31.0) (2022-08-03) - - -### Features - -* **hooks:** add `searchAsYouType` option to `` ([#3585](https://github.com/algolia/react-instantsearch/issues/3585)) ([c610385](https://github.com/algolia/react-instantsearch/commit/c610385cb9688b23b3e041e31b9edd60392b341d)) - - - -## [6.30.3](https://github.com/algolia/react-instantsearch/compare/v6.30.2...v6.30.3) (2022-08-01) - - -### Bug Fixes - -* **hooks:** replace `labelText` CSS class with `label` in `` to align with InstantSearch's CSS specifications ([#3583](https://github.com/algolia/react-instantsearch/issues/3583)) ([3e030ae](https://github.com/algolia/react-instantsearch/commit/3e030aedb9f285ff449eb82589bc6fea60b160cb)) - - - -## [6.30.2](https://github.com/algolia/react-instantsearch/compare/v6.30.1...v6.30.2) (2022-07-18) - - -### Bug Fixes - -* **hooks:** type of DynamicWidgets props ([#3566](https://github.com/algolia/react-instantsearch/issues/3566)) ([612c98b](https://github.com/algolia/react-instantsearch/commit/612c98b5a77fb9037185c4b5efda8c07663dbd1a)), closes [#3563](https://github.com/algolia/react-instantsearch/issues/3563) -* **hooks:** use single instance in ([#3561](https://github.com/algolia/react-instantsearch/issues/3561)) ([4c358be](https://github.com/algolia/react-instantsearch/commit/4c358bebfc91451b1610f677f89c595d7a427f1f)) - - - -## [6.30.1](https://github.com/algolia/react-instantsearch/compare/v6.30.0...v6.30.1) (2022-07-12) - - -### Bug Fixes - -* **hooks:** provide state and results APIs from "render" event ([#3554](https://github.com/algolia/react-instantsearch/issues/3554)) ([67d4788](https://github.com/algolia/react-instantsearch/commit/67d4788ab09ec2a57b43d53e8093b8c11120b761)) -* **hooks**: update instantsearch.js dependency ([#3557](https://github.com/algolia/react-instantsearch/issues/3557)) - - - -# [6.30.0](https://github.com/algolia/react-instantsearch/compare/v6.29.0...v6.30.0) (2022-07-05) - - -### Features - -* **core:** update instantsearch and helper ([#3539](https://github.com/algolia/react-instantsearch/issues/3539)) ([0ac2c7a](https://github.com/algolia/react-instantsearch/commit/0ac2c7a3f2e2a827721f5b2b7c69c54560f8574f)) - - - -# [6.29.0](https://github.com/algolia/react-instantsearch/compare/v6.28.0...v6.29.0) (2022-06-21) - - -### Bug Fixes - -* **HierarchicalMenu:** show full hierarchical parent values ([#3521](https://github.com/algolia/react-instantsearch/issues/3521)) ([79c3890](https://github.com/algolia/react-instantsearch/commit/79c3890848175a4d70311e5c3929c902bb953c10)) - - -### Features - -* **core:** sort parameters for improved cache rate ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) -* **core:** support client.search for sffv ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) - - - -# [6.28.0](https://github.com/algolia/react-instantsearch/compare/v6.27.0...v6.28.0) (2022-06-15) - - -### Bug Fixes - -* **hooks-server:** import react server via an expression ([#3515](https://github.com/algolia/react-instantsearch/issues/3515)) ([91b96f7](https://github.com/algolia/react-instantsearch/commit/91b96f743b9315ed5ea781681b77fc7f5604ab6e)), closes [#3512](https://github.com/algolia/react-instantsearch/issues/3512) -* **hooks-web:** fix duplicated key in ([#3513](https://github.com/algolia/react-instantsearch/issues/3513)) ([fc94d80](https://github.com/algolia/react-instantsearch/commit/fc94d806daf139f58b234cdc0b450da2efe861ee)) -* **hooks:** mount widgets in SSR to retrieve HTML ([#3518](https://github.com/algolia/react-instantsearch/issues/3518)) ([aa5f9d8](https://github.com/algolia/react-instantsearch/commit/aa5f9d84ddb6e97d05e6ad1baf2c6caa23891281)) -* **types:** allow useInstantSearch to be generic ([#3508](https://github.com/algolia/react-instantsearch/issues/3508)) ([6807232](https://github.com/algolia/react-instantsearch/commit/68072324cf302801502a1b4c3d06703e57b55a97)), closes [algolia/instantsearch.js#5060](https://github.com/algolia/instantsearch.js/issues/5060) -* **types:** support React 18 types ([#3481](https://github.com/algolia/react-instantsearch/issues/3481)) ([74cf8cb](https://github.com/algolia/react-instantsearch/commit/74cf8cb9be8ff3d113b57a50e7083df0d1bc94f2)) - - -### Features - -* **hooks:** introduce `useInstantSearch()` ([#3494](https://github.com/algolia/react-instantsearch/issues/3494)) ([74d522c](https://github.com/algolia/react-instantsearch/commit/74d522c032326658f2a0b8f0001bd593e0085208)) -* **hooks:** support React 18 Strict Mode ([#3514](https://github.com/algolia/react-instantsearch/issues/3514)) ([eeb67c7](https://github.com/algolia/react-instantsearch/commit/eeb67c7b5dc08c696c46d9538f104eeceecef388)) - - - -# [6.27.0](https://github.com/algolia/react-instantsearch/compare/v6.26.0...v6.27.0) (2022-06-07) - - -### Bug Fixes - -* **hooks-web:** don't pass widget props to ui components ([#3501](https://github.com/algolia/react-instantsearch/issues/3501)) ([5bd53c1](https://github.com/algolia/react-instantsearch/commit/5bd53c128ddeeea87f75ae89eb8f2324d476c70e)), closes [#3499](https://github.com/algolia/react-instantsearch/issues/3499) -* **SearchBox-hooks:** correctly pass widget props ([#3499](https://github.com/algolia/react-instantsearch/issues/3499)) ([2cdf906](https://github.com/algolia/react-instantsearch/commit/2cdf90602b7c2c5895124ef64c389ce574154386)), closes [#3498](https://github.com/algolia/react-instantsearch/issues/3498) - - -### Features - -* **hooks:** migrate to `useSyncExternalStore()` ([#3489](https://github.com/algolia/react-instantsearch/issues/3489)) ([81bbdf2](https://github.com/algolia/react-instantsearch/commit/81bbdf28f2d28d8b0081cfd7d9e84c3e33038dd2)) -* **hooks:** upgrade to InstantSearch.js 4.41.0 ([#3502](https://github.com/algolia/react-instantsearch/issues/3502)) ([0b76792](https://github.com/algolia/react-instantsearch/commit/0b76792ea0c4e2ac9fe742810d70ba1aee2a3e79)) - - - -# [6.26.0](https://github.com/algolia/react-instantsearch/compare/v6.25.0...v6.26.0) (2022-05-19) - - -### Features - -* **hooks-web:** expose `sendEvent` to `hitComponent` ([#3476](https://github.com/algolia/react-instantsearch/issues/3476)) ([5cc18d1](https://github.com/algolia/react-instantsearch/commit/5cc18d19d9f22305f33d92e43fd0aca2a5cb949a)) -* **react-instantsearch-core:** allow widgets to set their `$$widgetType` ([#3472](https://github.com/algolia/react-instantsearch/issues/3472)) ([1c436e1](https://github.com/algolia/react-instantsearch/commit/1c436e1429ab4230bbfea7c6d2474d141f5c5c64)) - - - -# [6.25.0](https://github.com/algolia/react-instantsearch/compare/v6.24.3...v6.25.0) (2022-05-17) - - -### Bug Fixes - -* **hooks-highlight:** make sure highlight and snippet don't show html-escaped content ([#3471](https://github.com/algolia/react-instantsearch/issues/3471)) ([c18ddd2](https://github.com/algolia/react-instantsearch/commit/c18ddd25faca37d6bfa3d1c28f6fc22ec5fcf6d8)) -* **hooks-server:** remove faulty UMD build ([#3465](https://github.com/algolia/react-instantsearch/issues/3465)) ([c1ddfe4](https://github.com/algolia/react-instantsearch/commit/c1ddfe408b411551ac8524877a9d65ded8133c42)) - - -### Features - -* **dom-maps:** expose GeoSearchContext ([#3468](https://github.com/algolia/react-instantsearch/issues/3468)) ([a61ff96](https://github.com/algolia/react-instantsearch/commit/a61ff96222bfd4f6301cf93bf95e2fa18b263d3c)), closes [#3448](https://github.com/algolia/react-instantsearch/issues/3448) -* **hooks-server:** support import from React 18 ([#3464](https://github.com/algolia/react-instantsearch/issues/3464)) ([0a13867](https://github.com/algolia/react-instantsearch/commit/0a13867f7dd5a8a18e0957b2072bbde3b02d6490)), closes [#3453](https://github.com/algolia/react-instantsearch/issues/3453) -* **hooks:** make InstantSearch type generic ([#3466](https://github.com/algolia/react-instantsearch/issues/3466)) ([b0905b7](https://github.com/algolia/react-instantsearch/commit/b0905b73bed558c62eedb7ae701be20c2ebe25c9)) - - - -## [6.24.3](https://github.com/algolia/react-instantsearch/compare/v6.24.2...v6.24.3) (2022-05-10) - - -### Bug Fixes - -* **numericmenu:** include range values in comparison with minmax bounds ([#3461](https://github.com/algolia/react-instantsearch/issues/3461)) ([e4c2682](https://github.com/algolia/react-instantsearch/commit/e4c268261dc42a6aa43d985934b53c82f8b71089)) - - - -## [6.24.2](https://github.com/algolia/react-instantsearch/compare/v6.24.1...v6.24.2) (2022-05-05) - - -### Bug Fixes - -* **hooks:** prevent infinite loops from render state ([#3455](https://github.com/algolia/react-instantsearch/issues/3455)) ([1799fc9](https://github.com/algolia/react-instantsearch/commit/1799fc9f78a4a5aafb54df339c3e211ff9187748)) - - - -## [6.24.1](https://github.com/algolia/react-instantsearch/compare/v6.24.0...v6.24.1) (2022-05-03) - - -### Bug Fixes - -* **types:** export correct types for react-instantsearch-hooks-web ([#3454](https://github.com/algolia/react-instantsearch/issues/3454)) ([a863430](https://github.com/algolia/react-instantsearch/commit/a8634306621f7a05a2b3056a6db25ccf8d9eabf0)) - - - -# [6.24.0](https://github.com/algolia/react-instantsearch/compare/v6.23.4...v6.24.0) (2022-04-28) - - -### Features - -* **hooks:** expose DOM components ([#3450](https://github.com/algolia/react-instantsearch/issues/3450)) ([5732e3d](https://github.com/algolia/react-instantsearch/commit/5732e3de732275911f94b26ba9e2c4165bdf77e7)) -* **hooks:** remove experimental warning ([#3446](https://github.com/algolia/react-instantsearch/issues/3446)) ([84c99fe](https://github.com/algolia/react-instantsearch/commit/84c99fe91d6906a877bec620b44c61d762f0ea57)) - - - -## [6.23.4](https://github.com/algolia/react-instantsearch/compare/v6.23.3...v6.23.4) (2022-04-21) - - -### Bug Fixes - -* **hooks:** forbid importing from instantsearch.js root path ([#3437](https://github.com/algolia/react-instantsearch/issues/3437)) ([82ef9ea](https://github.com/algolia/react-instantsearch/commit/82ef9eaaec42bc54f15796b5b031a8656330a45c)) -* **packages:** correctly mark peer dependency ([#3439](https://github.com/algolia/react-instantsearch/issues/3439)) ([51e8818](https://github.com/algolia/react-instantsearch/commit/51e8818fce224819230c8bf6dea2a08d71d9be29)), closes [#3428](https://github.com/algolia/react-instantsearch/issues/3428) - - - -## [6.23.3](https://github.com/algolia/react-instantsearch/compare/v6.23.2...v6.23.3) (2022-04-05) - - -### Bug Fixes - -* **facets:** show raw value in currentRefinements ([#3420](https://github.com/algolia/react-instantsearch/issues/3420)) ([1199ce6](https://github.com/algolia/react-instantsearch/commit/1199ce6bd4152e4b54bd2ee0e1f0c9d81021c7d5)), closes [#3412](https://github.com/algolia/react-instantsearch/issues/3412) -* **multi-index:** correctly set `searching` prop in multi-index result states ([#3419](https://github.com/algolia/react-instantsearch/issues/3419)) ([7f8e97e](https://github.com/algolia/react-instantsearch/commit/7f8e97e31b3dd5e49d3febef673f41f7dfa6d45d)) - - - -## [6.23.2](https://github.com/algolia/react-instantsearch/compare/v6.23.1...v6.23.2) (2022-04-04) - - -### Bug Fixes - -* **refinements:** use escaped value for refining ([#3412](https://github.com/algolia/react-instantsearch/issues/3412)) ([f2f5f6c](https://github.com/algolia/react-instantsearch/commit/f2f5f6cbfaed48a5c494daeb8789e8deebc64293)) -* support React 18 as peer dependency ([#3411](https://github.com/algolia/react-instantsearch/issues/3411)) ([38eb5a6](https://github.com/algolia/react-instantsearch/commit/38eb5a6a8fe92cb763a25f452bea78b189a6a82a)) - - -## [6.23.1](https://algolia/compare/v6.23.0...v6.23.1) (2022-03-30) - - -### Bug Fixes - -* **hooks:** compute initial search parameters from widget ([#3399](https://algolia/issues/3399)) ([b4bd933](https://algolia/commits/b4bd93358598bdc77a1aa858252e6eee23441345)) - - - -# [6.23.0](https://algolia/compare/v6.22.0...v6.23.0) (2022-03-23) - - -### Bug Fixes - -* **ssr:** perform initial multi-index search using a single request ([#3385](https://algolia/issues/3385)) ([b96809e](https://algolia/commits/b96809e5748d298350890647956cb7adbbb55650)) - - -### Features - -* **hooks:** allow additional widget properties to be passed from hooks ([#3359](https://algolia/issues/3359)) ([a047be4](https://algolia/commits/a047be45c7fce7ee28f7d6f61d2fbfa79e3ed2d0)) -* **hooks:** allow useHits and useInfiniteHit to be generic ([#3364](https://algolia/issues/3364)) ([8e66ad3](https://algolia/commits/8e66ad3ad587197c4811c60a5cab475137ca5afb)) -* **hooks:** mark initial results as "artificial" ([#3384](https://algolia/issues/3384)) ([937efdc](https://algolia/commits/937efdc71bae1d99270f8ecb5c5c9c501b3d7769)) - - - -# [6.22.0](https://github.com/algolia/react-instantsearch/compare/v6.21.1...v6.22.0) (2022-02-01) - - -### Bug Fixes - -* **hooks:** enable pause on exceptions on warning ([#3283](https://github.com/algolia/react-instantsearch/issues/3283)) ([ce3a6c3](https://github.com/algolia/react-instantsearch/commit/ce3a6c3f2700a05ae54a91278fd23fa64a97d733)) - - -### Features - -* **hooks:** introduce `useBreadcrumb()` ([#3245](https://github.com/algolia/react-instantsearch/issues/3245)) ([5bfbaaf](https://github.com/algolia/react-instantsearch/commit/5bfbaaf746e7632968ac9b30b73357bcb0b37e91)) - - - -## [6.21.1](https://github.com/algolia/react-instantsearch/compare/v6.21.0...v6.21.1) (2022-01-25) - - -### Bug Fixes - -* **hooks:** apply initial search parameters in useConnector ([#3276](https://github.com/algolia/react-instantsearch/issues/3276)) ([f85d679](https://github.com/algolia/react-instantsearch/commit/f85d6794c31eac61521fd8fc16b75673f02ed75b)) - - - -# [6.21.0](https://github.com/algolia/react-instantsearch/compare/v6.20.0...v6.21.0) (2022-01-24) - - -### Features - -* **hooks-server:** load data twice in the case of dynamic widget usage ([#3259](https://github.com/algolia/react-instantsearch/issues/3259)) ([9b4903b](https://github.com/algolia/react-instantsearch/commit/9b4903b2ea73d9d7e33729b87d9d55990e64312c)) -* **server:** load data twice in the case of dynamic widget usage ([#3268](https://github.com/algolia/react-instantsearch/issues/3268)) ([91cd085](https://github.com/algolia/react-instantsearch/commit/91cd085f9a323ed6b872f3a098f561007a72d0d2)), closes [/github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js#L14-L16](https://github.com//github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js/issues/L14-L16) - - - -# [6.20.0](https://github.com/algolia/react-instantsearch/compare/v6.19.0...v6.20.0) (2022-01-18) - - -### Bug Fixes - -* **hooks:** allow importing via require ([#3257](https://github.com/algolia/react-instantsearch/issues/3257)) ([6aa80b3](https://github.com/algolia/react-instantsearch/commit/6aa80b3647567199c3df1b90a07d708b223ce1fd)) - - -### Features - -* **hooks:** implement `useClearRefinements()` ([#3256](https://github.com/algolia/react-instantsearch/issues/3256)) ([930b83d](https://github.com/algolia/react-instantsearch/commit/930b83df4c4bbccbc3118f6ea1001f6a30a3d464)), closes [#3252](https://github.com/algolia/react-instantsearch/issues/3252) -* **hooks:** introduce `` ([#3261](https://github.com/algolia/react-instantsearch/issues/3261)) ([3527b94](https://github.com/algolia/react-instantsearch/commit/3527b9422de48a4a6b4bd752bd643e01cd5011d8)) -* **hooks:** introduce `usePoweredBy()` ([#3251](https://github.com/algolia/react-instantsearch/issues/3251)) ([a97230b](https://github.com/algolia/react-instantsearch/commit/a97230b89e3ba1df9bf2d21a6a9f9a70b45f41b8)) -* **hooks:** introduce `useToggleRefinement()` ([#3248](https://github.com/algolia/react-instantsearch/issues/3248)) ([a561c09](https://github.com/algolia/react-instantsearch/commit/a561c090a268e1c6ca1fa2d5bf72263cc47aa273)) - - - -# [6.19.0](https://github.com/algolia/react-instantsearch/compare/v6.18.0...v6.19.0) (2022-01-05) - - -### Features - -* **hooks:** bundle as es-module ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) -* **dependencies:** update to latest algoliasearch-helper ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) - - - -# [6.18.0](https://github.com/algolia/react-instantsearch/compare/v6.17.0...v6.18.0) (2021-12-16) - - -### Features - -* **dynamicWidgets:** send facets * and maxValuesPerFacet by default ([#3242](https://github.com/algolia/react-instantsearch/issues/3242)) ([c071776](https://github.com/algolia/react-instantsearch/commit/c07177670ac30dced55250774654e8b2a77b6739)) -* **hooks:** introduce `useNumericMenu()` ([#3237](https://github.com/algolia/react-instantsearch/issues/3237)) ([e3056c9](https://github.com/algolia/react-instantsearch/commit/e3056c9e2c64b5afafb7a736599a5cbf6137575b)) -* **hooks:** introduce `useInfiniteHits()` ([#3224](https://github.com/algolia/react-instantsearch/issues/3224)) ([177ec56](https://github.com/algolia/react-instantsearch/commit/177ec56af274670c2bf8599ba104b5544979bbe8)) - - - -# [6.17.0](https://github.com/algolia/react-instantsearch/compare/v6.16.0...v6.17.0) (2021-12-08) - - -### Bug Fixes - -* **hooks:** throw invariant violations in production ([#3217](https://github.com/algolia/react-instantsearch/issues/3217)) ([6d3f99c](https://github.com/algolia/react-instantsearch/commit/6d3f99ca91f470ee742ddc55e95f57b1f1801d7b)) - - -### Features - -* **hooks:** introduce `useMenu()` ([#3197](https://github.com/algolia/react-instantsearch/issues/3197)) ([15d1cc9](https://github.com/algolia/react-instantsearch/commit/15d1cc993437b111cd5a32f43ee1d2065c639ed4)) -* **hooks:** introduce `useRange()` ([#3198](https://github.com/algolia/react-instantsearch/issues/3198)) ([df1f1c8](https://github.com/algolia/react-instantsearch/commit/df1f1c8109dc684e74d3aee1bf0359f2a0e1b9f4)) -* **hooks:** introduce `` ([#3216](https://github.com/algolia/react-instantsearch/issues/3216)) ([d99aea6](https://github.com/algolia/react-instantsearch/commit/d99aea6cfe9dea86ae6b98ee3762373f4b3843f1)) -* **hooks:** introduce `useDynamicWidgets()` ([#3210](https://github.com/algolia/react-instantsearch/issues/3210)) ([29c2ea2](https://github.com/algolia/react-instantsearch/commit/29c2ea22b91a39d9eb40a044ae9aab85f2612db8)) -* **hooks:** introduce `useQueryRules()` ([#3212](https://github.com/algolia/react-instantsearch/issues/3212)) ([3ef1e1e](https://github.com/algolia/react-instantsearch/commit/3ef1e1e4116b3e58b2c2134d0c60fbb9f40c1501)) -* **hooks:** introduce SSR support ([#3221](https://github.com/algolia/react-instantsearch/issues/3221)) ([0a6b3ec](https://github.com/algolia/react-instantsearch/commit/0a6b3ec61942ad3849c6f078e21b3328679bffff)) -* **hooks:** introduce `useCurrentRefinements()` ([#3222](https://github.com/algolia/react-instantsearch/issues/3222)) ([7ebd8c3](https://github.com/algolia/react-instantsearch/commit/7ebd8c3da8c17b0bd7e0f8deab633b98fa052e7f)) - - - -# [6.16.0](https://github.com/algolia/react-instantsearch/compare/v6.15.0...v6.16.0) (2021-11-22) - - -### Bug Fixes - -* **PoweredBy:** support environments with `window` but no `location` ([#3186](https://github.com/algolia/react-instantsearch/issues/3186)) ([22ff23b](https://github.com/algolia/react-instantsearch/commit/22ff23b67554683567393114c2f53cacec44f4a6)) - - -### Features - -* **DynamicWidgets:** release as stable ([#3090](https://github.com/algolia/react-instantsearch/issues/3090)) ([a4a1d9e](https://github.com/algolia/react-instantsearch/commit/a4a1d9e032b31c611d5d73fdda3a03ad705f5c68)) -* **hooks:** introduce `usePagination()` ([#3182](https://github.com/algolia/react-instantsearch/issues/3182)) ([d8b1b86](https://github.com/algolia/react-instantsearch/commit/d8b1b867bb598e801f1350e81b4a4220a8e528d7)) -* **hooks:** introduce `useSortBy()` ([#3190](https://github.com/algolia/react-instantsearch/issues/3190)) ([5cce33b](https://github.com/algolia/react-instantsearch/commit/5cce33b48032548fed76b592ee0201e3c42fc3c4)) -* **hooks:** introduce `useHierarchicalMenu()` ([#3199](https://github.com/algolia/react-instantsearch/issues/3199)) ([b347061](https://github.com/algolia/react-instantsearch/commit/b3470611b962ef55c55576c65a6307abc54e5efd)) - - - -# [6.15.0](https://github.com/algolia/react-instantsearch/compare/v6.14.0...v6.15.0) (2021-10-27) - - -### Bug Fixes - -* **metadata:** stricter detection of user agent ([#3184](https://github.com/algolia/react-instantsearch/issues/3184)) ([994c8ae](https://github.com/algolia/react-instantsearch/commit/994c8ae055fc23a1a067d111d2f4727b1c7bf8ca)) - - -### Features - -* **hooks:** introduce `useConfigure()` ([#3181](https://github.com/algolia/react-instantsearch/issues/3181)) ([aa2eb9b](https://github.com/algolia/react-instantsearch/commit/aa2eb9baec6335f8a3523ee8b9b761a217cfc734)) - - - -# [6.14.0](https://github.com/algolia/react-instantsearch/compare/v6.13.0...v6.14.0) (2021-10-26) - - -### Features - -* **dependencies:** update algoliasearch-helper ([#3176](https://github.com/algolia/react-instantsearch/issues/3176)) ([a8708a3](https://github.com/algolia/react-instantsearch/commit/a8708a33f31632000bc827b076539b1cca7adf6f)) -* **metadata:** expose widget information ([#3145](https://github.com/algolia/react-instantsearch/issues/3145)) ([46cddf8](https://github.com/algolia/react-instantsearch/commit/46cddf8fcc0291beaa34b04da7aaaa7f2566e52e)) - - - -# [6.13.0](https://github.com/algolia/react-instantsearch/compare/v6.12.1...v6.13.0) (2021-10-19) - -This is the initial release of the experimental **React InstantSearch Hooks** package. Check out the [**Getting Started**](https://github.com/algolia/react-instantsearch/blob/e8d72cb1c7c45300ef7c273f1f163beb6dc57622/packages/react-instantsearch-hooks/README.md#getting-started) guide. - -### Bug Fixes - -- **core:** accept objects for `hitComponent` ([#3087](https://github.com/algolia/react-instantsearch/issues/3087)) ([4ae23d4](https://github.com/algolia/react-instantsearch/commit/4ae23d432a01ccbefff1fcdc865120aeca4d3efc)) - -### Features - -- **hooks:** add InstantSearch and Index components ([#3133](https://github.com/algolia/react-instantsearch/issues/3133)) ([8e3370d](https://github.com/algolia/react-instantsearch/commit/8e3370ddb7d5e42b8b9a5ff6a1e4255490de7dbe)) -- **hooks:** bootstrap Core package ([#3132](https://github.com/algolia/react-instantsearch/issues/3132)) ([d459e62](https://github.com/algolia/react-instantsearch/commit/d459e62f5cae4c98427ab302531873f5ee23d149)) -- **hooks:** display experimental warning ([#3149](https://github.com/algolia/react-instantsearch/issues/3149)) ([623577c](https://github.com/algolia/react-instantsearch/commit/623577c50cd0c04cd87f719edafdcfa04b5527b6)) -- **hooks:** export types ([#3159](https://github.com/algolia/react-instantsearch/issues/3159)) ([182348b](https://github.com/algolia/react-instantsearch/commit/182348b4a901823a7a41aee5d2b3bdc025cce48f)) -- **hooks:** expose `displayName` on Contexts ([#3168](https://github.com/algolia/react-instantsearch/issues/3168)) ([dafd3c6](https://github.com/algolia/react-instantsearch/commit/dafd3c66d05fbec09ebf907209ac25f55804e6f5)) -- **hooks:** friendly error when using Hooks with Core ([#3150](https://github.com/algolia/react-instantsearch/issues/3150)) ([d547ccf](https://github.com/algolia/react-instantsearch/commit/d547ccf7951299e2f6b1771e02fce052696ff65a)) -- **hooks:** introduce `useConnector()` ([#3137](https://github.com/algolia/react-instantsearch/issues/3137)) ([53e8afd](https://github.com/algolia/react-instantsearch/commit/53e8afd093b9950351467a16b82d528207ac34d2)) -- **hooks:** introduce `useHits()` ([#3147](https://github.com/algolia/react-instantsearch/issues/3147)) ([cc25cff](https://github.com/algolia/react-instantsearch/commit/cc25cff06e5ec216cba40fb8261372bc327001b6)) -- **hooks:** introduce `useRefinementList()` ([#3152](https://github.com/algolia/react-instantsearch/issues/3152)) ([0385cd9](https://github.com/algolia/react-instantsearch/commit/0385cd971635a8423ad687fab451d0778358389e)) -- **hooks:** introduce `useSearchBox()` ([#3146](https://github.com/algolia/react-instantsearch/issues/3146)) ([0d2c7f9](https://github.com/algolia/react-instantsearch/commit/0d2c7f9bd25b88cf725a1babd3b228ac804644c7)) -- **hooks:** trigger single network request on load ([#3167](https://github.com/algolia/react-instantsearch/issues/3167)) ([ff1ea49](https://github.com/algolia/react-instantsearch/commit/ff1ea49079a7800fd61ba99ceeb74b9f513eb99d)) -- **hooks:** type `useConnector()` return as render state ([#3169](https://github.com/algolia/react-instantsearch/issues/3169)) ([a801468](https://github.com/algolia/react-instantsearch/commit/a80146860164a092d2c90ee0aa4fcef88d5b675f)) -- **hooks:** update GitHub bug reports link ([#3157](https://github.com/algolia/react-instantsearch/issues/3157)) ([568b5c8](https://github.com/algolia/react-instantsearch/commit/568b5c83849a3927417907706656c3835163f216)) - - - -## [6.12.1](https://github.com/algolia/react-instantsearch/compare/v6.12.0...v6.12.1) (2021-08-02) - - -### Bug Fixes - -* **server side rendering:** return a value from mock currentRefinement/metadata ([#3078](https://github.com/algolia/react-instantsearch/issues/3078)) ([09f802b](https://github.com/algolia/react-instantsearch/commit/09f802b)) - - - -# [6.12.0](https://github.com/algolia/react-instantsearch/compare/v6.11.2...v6.12.0) (2021-07-06) - - -### Bug Fixes - -* **HitsPerPage:** Adds id prop to HitsPerPage, Select components ([#3072](https://github.com/algolia/react-instantsearch/issues/3072)) ([bc75d75](https://github.com/algolia/react-instantsearch/commit/bc75d75)) -* **MenuSelect:** Adds id prop to MenuSelect ([#3073](https://github.com/algolia/react-instantsearch/issues/3073)) ([fddaaef](https://github.com/algolia/react-instantsearch/commit/fddaaef)) -* **SearchBox:** Adds inputId prop to SearchBox ([#3074](https://github.com/algolia/react-instantsearch/issues/3074)) ([a05f6a4](https://github.com/algolia/react-instantsearch/commit/a05f6a4)) -* **SortBy:** Adds `id` prop to `SortBy`, `Select` components ([#3068](https://github.com/algolia/react-instantsearch/issues/3068)) ([1f2797f](https://github.com/algolia/react-instantsearch/commit/1f2797f)) - - -### Features - -* **DynamicWidgets:** add implementation ([#3056](https://github.com/algolia/react-instantsearch/issues/3056)) ([691ef87](https://github.com/algolia/react-instantsearch/commit/691ef87)) -* **facets:** add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu ([#3067](https://github.com/algolia/react-instantsearch/issues/3067)) ([731d9ba](https://github.com/algolia/react-instantsearch/commit/731d9ba)) - - - -## [6.11.2](https://github.com/algolia/react-instantsearch/compare/v6.11.1...v6.11.2) (2021-06-28) - - -### Bug Fixes - -* **maps:** leave zoom in place if the bounds did not change ([#3050](https://github.com/algolia/react-instantsearch/issues/3050)) ([c430598](https://github.com/algolia/react-instantsearch/commit/c430598)) - - - -## [6.11.1](https://github.com/algolia/react-instantsearch/compare/v6.11.0...v6.11.1) (2021-06-09) - - -### Bug Fixes - -* **RefinementList:** prevent searchable component to refine on empty list ([#3059](https://github.com/algolia/react-instantsearch/issues/3059)) ([04f3644](https://github.com/algolia/react-instantsearch/commit/04f3644)) - - - -# [6.11.0](https://github.com/algolia/react-instantsearch/compare/v6.10.3...v6.11.0) (2021-05-04) - - -### Features - -* **connectNumericMenu:** add support for floating point values ([#3047](https://github.com/algolia/react-instantsearch/issues/3047)) ([091bf57](https://github.com/algolia/react-instantsearch/commit/091bf57)) - - - -## [6.10.3](https://github.com/algolia/react-instantsearch/compare/v6.10.2...v6.10.3) (2021-03-03) - - -### Bug Fixes - -* **RelevantSort:** Rename `SmartSort` widget to `RelevantSort` ([#3026](https://github.com/algolia/react-instantsearch/issues/3026)) ([47d11bf](https://github.com/algolia/react-instantsearch/commit/47d11bf)) - - - -## [6.10.2](https://github.com/algolia/react-instantsearch/compare/v6.10.1...v6.10.2) (2021-03-03) - - -### Bug Fixes - -* **infiniteHits:** fix stale hits issue ([#3021](https://github.com/algolia/react-instantsearch/issues/3021)) ([a9a29c7](https://github.com/algolia/react-instantsearch/commit/a9a29c7)) - - - -## [6.10.1](https://github.com/algolia/react-instantsearch/compare/v6.10.0...v6.10.1) (2021-03-02) - - -### Bug Fixes - -* **SmartSort:** make `textComponent` and `buttonTextComponent` optional ([#3014](https://github.com/algolia/react-instantsearch/issues/3014)) ([682ee6d](https://github.com/algolia/react-instantsearch/commit/682ee6d)) - - - -# [6.10.0](https://github.com/algolia/react-instantsearch/compare/v6.9.0...v6.10.0) (2021-02-23) - - -### Bug Fixes - -* **infiniteHits:** do not cache the cached hits ([#3011](https://github.com/algolia/react-instantsearch/issues/3011)) ([b56f5f7](https://github.com/algolia/react-instantsearch/commit/b56f5f7)) - - -### Features - -* **smartSort:** add widget ([#3009](https://github.com/algolia/react-instantsearch/issues/3009)) ([4cc8412](https://github.com/algolia/react-instantsearch/commit/4cc8412)), closes [#3010](https://github.com/algolia/react-instantsearch/issues/3010) - - - -# [6.9.0](https://github.com/algolia/react-instantsearch/compare/v6.8.3...v6.9.0) (2021-02-03) - - -### Features - -* **answers:** add `EXPERIMENTAL_Answers` widget ([#2996](https://github.com/algolia/react-instantsearch/issues/2996)) ([55e4191](https://github.com/algolia/react-instantsearch/commit/55e4191)), closes [#3005](https://github.com/algolia/react-instantsearch/issues/3005) - - - -## [6.8.3](https://github.com/algolia/react-instantsearch/compare/v6.8.2...v6.8.3) (2021-01-22) - - -### Bug Fixes - -* upgrade prop-types dependency to 15.6+ ([#3003](https://github.com/algolia/react-instantsearch/issues/3003)) ([fc03496](https://github.com/algolia/react-instantsearch/commit/fc03496)) - - - -## [6.8.2](https://github.com/algolia/react-instantsearch/compare/v6.8.1...v6.8.2) (2020-10-21) - - -### Bug Fixes - -* **ssr:** provide metadata default value ([0a2f34c](https://github.com/algolia/react-instantsearch/commit/0a2f34c)) - - - -## [6.8.1](https://github.com/algolia/react-instantsearch/compare/v6.8.0...v6.8.1) (2020-10-14) - - -### Bug Fixes - -* **ssr:** hydrate metadata with a value ([9249c19](https://github.com/algolia/react-instantsearch/commit/9249c19)) - - - -# [6.8.0](https://github.com/algolia/react-instantsearch/compare/v6.7.0...v6.8.0) (2020-10-14) - - -### Bug Fixes - -* **ssr:** make sure metadata is available on initial render ([#2973](https://github.com/algolia/react-instantsearch/issues/2973)) ([be43b65](https://github.com/algolia/react-instantsearch/commit/be43b65)), closes [#2972](https://github.com/algolia/react-instantsearch/issues/2972) -* add missing dependencies ([#2975](https://github.com/algolia/react-instantsearch/issues/2975)) ([22ecb3c](https://github.com/algolia/react-instantsearch/commit/22ecb3c)) -* **ConfigureRelatedItems:** support nested attributes ([#2967](https://github.com/algolia/react-instantsearch/issues/2967)) ([86dfe86](https://github.com/algolia/react-instantsearch/commit/86dfe86)) -* **ssr:** allow "params" to be optional in custom clients ([#2961](https://github.com/algolia/react-instantsearch/issues/2961)) ([c3e3d2e](https://github.com/algolia/react-instantsearch/commit/c3e3d2e)), closes [#2958](https://github.com/algolia/react-instantsearch/issues/2958) - - - -# [6.7.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.7.0) (2020-07-20) - - -### Bug Fixes - -* **core:** appending successful index search results by returning new object reference ([#2953](https://github.com/algolia/react-instantsearch/issues/2953)) ([0a711a7](https://github.com/algolia/react-instantsearch/commit/0a711a7)) -* **ssr:** remove second instance of "query" in the response "params" for SSR ([#2945](https://github.com/algolia/react-instantsearch/issues/2945)) ([bf837c5](https://github.com/algolia/react-instantsearch/commit/bf837c5)), closes [#2941](https://github.com/algolia/react-instantsearch/issues/2941) - - -### Features - -* **infinite-hits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.6.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.6.0) (2020-06-15) - - -### Features - -* **infiniteHits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.5.0](https://github.com/algolia/react-instantsearch/compare/v6.4.0...v6.5.0) (2020-05-18) - - -### Bug Fixes - -* **connectQueryRules:** fix crash when using connectQueryRules with multiple indexes ([#2903](https://github.com/algolia/react-instantsearch/issues/2903)) ([c66d612](https://github.com/algolia/react-instantsearch/commit/c66d612)) -* **core:** fix maximum call stack size exceeded ([#2926](https://github.com/algolia/react-instantsearch/issues/2926)) ([7e883df](https://github.com/algolia/react-instantsearch/commit/7e883df)) - - -### Features - -* **SearchBox:** provide input element ref ([#2913](https://github.com/algolia/react-instantsearch/issues/2913)) ([b41bff2](https://github.com/algolia/react-instantsearch/commit/b41bff2)) - - - -# [6.4.0](https://github.com/algolia/react-instantsearch/compare/v6.3.0...v6.4.0) (2020-03-18) - - -### Bug Fixes - -* **deps:** fix "too much recursion" error with circular deps ([#2899](https://github.com/algolia/react-instantsearch/issues/2899)) ([c5f27a1](https://github.com/algolia/react-instantsearch/commit/c5f27a1)) - - - -# [6.3.0](https://github.com/algolia/react-instantsearch/compare/v6.2.0...v6.3.0) (2020-01-30) - - -### Features - -* **algoliasearch:** add support for algoliasearch v4 ([#2890](https://github.com/algolia/react-instantsearch/issues/2890)) ([c6c7382](https://github.com/algolia/react-instantsearch/commit/c6c7382)) - - - -# [6.2.0](https://github.com/algolia/react-instantsearch/compare/v6.1.0...v6.2.0) (2020-01-20) - - -### Bug Fixes - -* **deps:** update dependency algoliasearch to v3.35.1 ([#2802](https://github.com/algolia/react-instantsearch/issues/2802)) ([cfb91f0](https://github.com/algolia/react-instantsearch/commit/cfb91f0)) -* **widgets:** rename `ExperimentalConfigureRelatedItems` compon… ([#2891](https://github.com/algolia/react-instantsearch/issues/2891)) ([b910df2](https://github.com/algolia/react-instantsearch/commit/b910df2)) - - -### Features - -* **insights:** add getInsightsAnonymousUserToken helper ([#2887](https://github.com/algolia/react-instantsearch/issues/2887)) ([b5fe4f7](https://github.com/algolia/react-instantsearch/commit/b5fe4f7)) -* **widgets:** introduce `ConfigureRelatedItems` as experimental ([#2880](https://github.com/algolia/react-instantsearch/issues/2880)) ([923cd43](https://github.com/algolia/react-instantsearch/commit/923cd43)) - - - -# [6.1.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0...v6.1.0) (2019-12-17) - - -### Bug Fixes - -* **connectNumericMenu:** support numeric refinement 0 ([#2882](https://github.com/algolia/react-instantsearch/issues/2882)) ([30bd9fd](https://github.com/algolia/react-instantsearch/commit/30bd9fd)) -* **deps:** update dependency next to v9.1.1 ([9d49d33](https://github.com/algolia/react-instantsearch/commit/9d49d33)) -* **helper:** rely on stable version of algoliasearch-helper ([#2871](https://github.com/algolia/react-instantsearch/issues/2871)) ([e3531a1](https://github.com/algolia/react-instantsearch/commit/e3531a1)) - - -### Features - -* **insights:** show an error when 'clickAnalytics: true' is missing. ([#2877](https://github.com/algolia/react-instantsearch/issues/2877)) ([621656a](https://github.com/algolia/react-instantsearch/commit/621656a)) -* **voice:** add additionalQueryParameters ([#2366](https://github.com/algolia/react-instantsearch/issues/2366)) ([3a45b2c](https://github.com/algolia/react-instantsearch/commit/3a45b2c)) - - - -# [6.0.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.2...v6.0.0) (2019-10-28) - - - -# [6.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2019-10-25) - - -### Bug Fixes - -* serialize cache value on hydrate ([#2862](https://github.com/algolia/react-instantsearch/issues/2862)) ([3319665](https://github.com/algolia/react-instantsearch/commit/3319665)), closes [#2828](https://github.com/algolia/react-instantsearch/issues/2828) - - - -# [6.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.1) (2019-10-18) - - -### Bug Fixes - -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **deps:** update dependency antd to v3.19.3 ([#2530](https://github.com/algolia/react-instantsearch/issues/2530)) ([73636c5](https://github.com/algolia/react-instantsearch/commit/73636c5)) -* **deps:** update dependency antd to v3.19.4 ([#2559](https://github.com/algolia/react-instantsearch/issues/2559)) ([c3e8267](https://github.com/algolia/react-instantsearch/commit/c3e8267)) -* **deps:** update dependency antd to v3.19.5 ([#2560](https://github.com/algolia/react-instantsearch/issues/2560)) ([72efd31](https://github.com/algolia/react-instantsearch/commit/72efd31)) -* **deps:** update dependency antd to v3.19.6 ([#2564](https://github.com/algolia/react-instantsearch/issues/2564)) ([654f986](https://github.com/algolia/react-instantsearch/commit/654f986)) -* **deps:** update dependency antd to v3.19.7 ([#2573](https://github.com/algolia/react-instantsearch/issues/2573)) ([7e963ad](https://github.com/algolia/react-instantsearch/commit/7e963ad)) -* **deps:** update dependency antd to v3.19.8 ([#2584](https://github.com/algolia/react-instantsearch/issues/2584)) ([34dd9b2](https://github.com/algolia/react-instantsearch/commit/34dd9b2)) -* **deps:** update dependency antd to v3.20.0 ([#2611](https://github.com/algolia/react-instantsearch/issues/2611)) ([b976c67](https://github.com/algolia/react-instantsearch/commit/b976c67)) -* **deps:** update dependency antd to v3.20.1 ([#2635](https://github.com/algolia/react-instantsearch/issues/2635)) ([792ad9c](https://github.com/algolia/react-instantsearch/commit/792ad9c)) -* **deps:** update dependency antd to v3.20.2 ([#2655](https://github.com/algolia/react-instantsearch/issues/2655)) ([301c2d8](https://github.com/algolia/react-instantsearch/commit/301c2d8)) -* **deps:** update dependency antd to v3.20.3 ([#2658](https://github.com/algolia/react-instantsearch/issues/2658)) ([d078e70](https://github.com/algolia/react-instantsearch/commit/d078e70)) -* **deps:** update dependency antd to v3.20.5 ([#2686](https://github.com/algolia/react-instantsearch/issues/2686)) ([42ef821](https://github.com/algolia/react-instantsearch/commit/42ef821)) -* **deps:** update dependency antd to v3.20.6 ([#2711](https://github.com/algolia/react-instantsearch/issues/2711)) ([927fbfe](https://github.com/algolia/react-instantsearch/commit/927fbfe)) -* **deps:** update dependency antd to v3.20.7 ([#2712](https://github.com/algolia/react-instantsearch/issues/2712)) ([1830952](https://github.com/algolia/react-instantsearch/commit/1830952)) -* **deps:** update dependency antd to v3.21.1 ([#2736](https://github.com/algolia/react-instantsearch/issues/2736)) ([39a51a6](https://github.com/algolia/react-instantsearch/commit/39a51a6)) -* **deps:** update dependency antd to v3.21.2 ([#2738](https://github.com/algolia/react-instantsearch/issues/2738)) ([a7a998a](https://github.com/algolia/react-instantsearch/commit/a7a998a)) -* **deps:** update dependency antd to v3.21.4 ([#2747](https://github.com/algolia/react-instantsearch/issues/2747)) ([60012be](https://github.com/algolia/react-instantsearch/commit/60012be)) -* **deps:** update dependency antd to v3.22.0 ([#2758](https://github.com/algolia/react-instantsearch/issues/2758)) ([9cda468](https://github.com/algolia/react-instantsearch/commit/9cda468)) -* **deps:** update dependency antd to v3.22.2 ([#2791](https://github.com/algolia/react-instantsearch/issues/2791)) ([ff1f5d9](https://github.com/algolia/react-instantsearch/commit/ff1f5d9)) -* **deps:** update dependency antd to v3.23.2 ([#2814](https://github.com/algolia/react-instantsearch/issues/2814)) ([a190410](https://github.com/algolia/react-instantsearch/commit/a190410)) -* **deps:** update dependency lodash to v4.17.13 ([c4974cf](https://github.com/algolia/react-instantsearch/commit/c4974cf)) -* **deps:** update dependency lodash to v4.17.14 ([#2647](https://github.com/algolia/react-instantsearch/issues/2647)) ([a2d2dd5](https://github.com/algolia/react-instantsearch/commit/a2d2dd5)) -* **deps:** update dependency lodash to v4.17.15 ([#2684](https://github.com/algolia/react-instantsearch/issues/2684)) ([354143f](https://github.com/algolia/react-instantsearch/commit/354143f)) -* **deps:** update dependency next to v9 ([#2638](https://github.com/algolia/react-instantsearch/issues/2638)) ([d22f61d](https://github.com/algolia/react-instantsearch/commit/d22f61d)) -* **deps:** update dependency next to v9.0.1 ([#2652](https://github.com/algolia/react-instantsearch/issues/2652)) ([2c2dab9](https://github.com/algolia/react-instantsearch/commit/2c2dab9)) -* **deps:** update dependency next to v9.0.2 ([#2662](https://github.com/algolia/react-instantsearch/issues/2662)) ([6fa4c5e](https://github.com/algolia/react-instantsearch/commit/6fa4c5e)) -* **deps:** update dependency next to v9.0.3 ([#2724](https://github.com/algolia/react-instantsearch/issues/2724)) ([f51b04b](https://github.com/algolia/react-instantsearch/commit/f51b04b)) -* **deps:** update dependency next to v9.0.4 ([#2767](https://github.com/algolia/react-instantsearch/issues/2767)) ([9af9180](https://github.com/algolia/react-instantsearch/commit/9af9180)) -* **deps:** update dependency next to v9.0.5 ([#2789](https://github.com/algolia/react-instantsearch/issues/2789)) ([0a75f41](https://github.com/algolia/react-instantsearch/commit/0a75f41)) -* **deps:** update dependency qs to v6.8.0 ([#2757](https://github.com/algolia/react-instantsearch/issues/2757)) ([8bffb87](https://github.com/algolia/react-instantsearch/commit/8bffb87)) -* **deps:** update dependency react-compound-slider to v2.1.0 ([#2610](https://github.com/algolia/react-instantsearch/issues/2610)) ([3389ee5](https://github.com/algolia/react-instantsearch/commit/3389ee5)) -* **deps:** update dependency react-compound-slider to v2.2.0 ([#2649](https://github.com/algolia/react-instantsearch/issues/2649)) ([7b81af1](https://github.com/algolia/react-instantsearch/commit/7b81af1)) -* **deps:** update dependency react-native-vector-icons to v6.5.0 ([#2520](https://github.com/algolia/react-instantsearch/issues/2520)) ([5f7f5b6](https://github.com/algolia/react-instantsearch/commit/5f7f5b6)) -* **deps:** update dependency react-native-vector-icons to v6.6.0 ([#2599](https://github.com/algolia/react-instantsearch/issues/2599)) ([b6bb199](https://github.com/algolia/react-instantsearch/commit/b6bb199)) -* **deps:** update dependency react-router-dom to v5.0.1 ([#2506](https://github.com/algolia/react-instantsearch/issues/2506)) ([d762230](https://github.com/algolia/react-instantsearch/commit/d762230)) -* **highlight:** switch to index as key ([#2691](https://github.com/algolia/react-instantsearch/issues/2691)) ([17e75d1](https://github.com/algolia/react-instantsearch/commit/17e75d1)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### chore - -* **release:** 6.0.0-beta.1 ([#2861](https://github.com/algolia/react-instantsearch/issues/2861)) ([cb56ca0](https://github.com/algolia/react-instantsearch/commit/cb56ca0)), closes [#2023](https://github.com/algolia/react-instantsearch/issues/2023) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2203](https://github.com/algolia/react-instantsearch/issues/2203) [#2432](https://github.com/algolia/react-instantsearch/issues/2432) [#2444](https://github.com/algolia/react-instantsearch/issues/2444) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2454](https://github.com/algolia/react-instantsearch/issues/2454) [#2455](https://github.com/algolia/react-instantsearch/issues/2455) [#2459](https://github.com/algolia/react-instantsearch/issues/2459) [#2458](https://github.com/algolia/react-instantsearch/issues/2458) [#2460](https://github.com/algolia/react-instantsearch/issues/2460) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2446](https://github.com/algolia/react-instantsearch/issues/2446) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2466](https://github.com/algolia/react-instantsearch/issues/2466) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2555](https://github.com/algolia/react-instantsearch/issues/2555) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2349](https://github.com/algolia/react-instantsearch/issues/2349) [#2570](https://github.com/algolia/react-instantsearch/issues/2570) [#2462](https://github.com/algolia/react-instantsearch/issues/2462) [#2600](https://github.com/algolia/react-instantsearch/issues/2600) [#2468](https://github.com/algolia/react-instantsearch/issues/2468) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2621](https://github.com/algolia/react-instantsearch/issues/2621) [#2627](https://github.com/algolia/react-instantsearch/issues/2627) [#2644](https://github.com/algolia/react-instantsearch/issues/2644) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2645](https://github.com/algolia/react-instantsearch/issues/2645) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2643](https://github.com/algolia/react-instantsearch/issues/2643) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2722](https://github.com/algolia/react-instantsearch/issues/2722) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2701](https://github.com/algolia/react-instantsearch/issues/2701) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2530](https://github.com/algolia/react-instantsearch/issues/2530) [#2559](https://github.com/algolia/react-instantsearch/issues/2559) [#2560](https://github.com/algolia/react-instantsearch/issues/2560) [#2564](https://github.com/algolia/react-instantsearch/issues/2564) [#2573](https://github.com/algolia/react-instantsearch/issues/2573) [#2584](https://github.com/algolia/react-instantsearch/issues/2584) [#2611](https://github.com/algolia/react-instantsearch/issues/2611) [#2635](https://github.com/algolia/react-instantsearch/issues/2635) [#2655](https://github.com/algolia/react-instantsearch/issues/2655) [#2658](https://github.com/algolia/react-instantsearch/issues/2658) [#2686](https://github.com/algolia/react-instantsearch/issues/2686) [#2711](https://github.com/algolia/react-instantsearch/issues/2711) [#2712](https://github.com/algolia/react-instantsearch/issues/2712) [#2736](https://github.com/algolia/react-instantsearch/issues/2736) [#2738](https://github.com/algolia/react-instantsearch/issues/2738) [#2747](https://github.com/algolia/react-instantsearch/issues/2747) [#2758](https://github.com/algolia/react-instantsearch/issues/2758) [#2647](https://github.com/algolia/react-instantsearch/issues/2647) [#2684](https://github.com/algolia/react-instantsearch/issues/2684) [#2638](https://github.com/algolia/react-instantsearch/issues/2638) [#2652](https://github.com/algolia/react-instantsearch/issues/2652) [#2662](https://github.com/algolia/react-instantsearch/issues/2662) [#2724](https://github.com/algolia/react-instantsearch/issues/2724) [#2767](https://github.com/algolia/react-instantsearch/issues/2767) [#2757](https://github.com/algolia/react-instantsearch/issues/2757) [#2610](https://github.com/algolia/react-instantsearch/issues/2610) [#2649](https://github.com/algolia/react-instantsearch/issues/2649) [#2520](https://github.com/algolia/react-instantsearch/issues/2520) [#2599](https://github.com/algolia/react-instantsearch/issues/2599) [#2506](https://github.com/algolia/react-instantsearch/issues/2506) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2688](https://github.com/algolia/react-instantsearch/issues/2688) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2535](https://github.com/algolia/react-instantsearch/issues/2535) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2834](https://github.com/algolia/react-instantsearch/issues/2834) [#2845](https://github.com/algolia/react-instantsearch/issues/2845) [#2842](https://github.com/algolia/react-instantsearch/issues/2842) [#2852](https://github.com/algolia/react-instantsearch/issues/2852) [#2853](https://github.com/algolia/react-instantsearch/issues/2853) - - -### BREAKING CHANGES - -* **release:** translation will render default value if passed undefined as value - -* chore(lodash): remove imports - -* fix(translation): allow undefined value to be passed on purpose -* **release:** no longer do we allow paths like `attribute[5].something`, or other indexed forms, only `.` is allowed as special key. - -All existing tests still pass, and we never documented you could use `lodash.get` patterns other than `.`. - -* feat(get): accept array & bracked-separated string - -moved to utils at the same time - -* fix typo - -* feedback: test for undefined behaviour - -* chore(size): update expectation - -this will go down afterwards, but for now there's some more duplication - - - -# [6.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.0) (2019-08-21) - -[Migration guide](MIGRATION.md) - -### Bug Fixes - -* **react 17 compat:** upgrade RangeInput lifecycle ([#2289](https://github.com/algolia/react-instantsearch/issues/2289)) ([110b1af](https://github.com/algolia/react-instantsearch/commit/110b1af)) -* **react 17 compat:** upgrade RangeSlider lifecycle ([#2290](https://github.com/algolia/react-instantsearch/issues/2290)) ([69a7f53](https://github.com/algolia/react-instantsearch/commit/69a7f53)) -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **core:** searchState can be non-Object object ([#2722](https://github.com/algolia/react-instantsearch/issues/2722)) ([dea493c](https://github.com/algolia/react-instantsearch/commit/dea493c)), closes [#2568](https://github.com/algolia/react-instantsearch/issues/2568) -* **createConnector:** new React life cycles ([#2357](https://github.com/algolia/react-instantsearch/issues/2357)) ([fc10640](https://github.com/algolia/react-instantsearch/commit/fc10640)) -* **createInstantSearchManager:** do not trigger search on index update ([#2552](https://github.com/algolia/react-instantsearch/issues/2552)) ([e209362](https://github.com/algolia/react-instantsearch/commit/e209362)) -* **geo:** check for undefined in isEqual ([#2643](https://github.com/algolia/react-instantsearch/issues/2643)) ([a544231](https://github.com/algolia/react-instantsearch/commit/a544231)), closes [#2467](https://github.com/algolia/react-instantsearch/issues/2467) -* **geo:** remove lifecycle compat ([#2644](https://github.com/algolia/react-instantsearch/issues/2644)) ([2b2b898](https://github.com/algolia/react-instantsearch/commit/2b2b898)), closes [#2626](https://github.com/algolia/react-instantsearch/issues/2626) -* **highlight:** switch to index as key ([#2690](https://github.com/algolia/react-instantsearch/issues/2690)) ([51de682](https://github.com/algolia/react-instantsearch/commit/51de682)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **peerDependencies:** update React ([#2626](https://github.com/algolia/react-instantsearch/issues/2626)) ([6ccad49](https://github.com/algolia/react-instantsearch/commit/6ccad49)) -* **ssr:** avoid duplicate serializing ([#2726](https://github.com/algolia/react-instantsearch/issues/2726)) ([c768b1a](https://github.com/algolia/react-instantsearch/commit/c768b1a)) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### Code Refactoring - -* **lodash:** get ([#2461](https://github.com/algolia/react-instantsearch/issues/2461)) ([527b879](https://github.com/algolia/react-instantsearch/commit/527b879)) -* **lodash:** has ([#2434](https://github.com/algolia/react-instantsearch/issues/2434)) ([75a4a15](https://github.com/algolia/react-instantsearch/commit/75a4a15)) -* **lodash:** has been fully removed - -### Features - -* **autocomplete:** add queryID & position to provided hits ([#2687](https://github.com/algolia/react-instantsearch/issues/2687)) ([e453dab](https://github.com/algolia/react-instantsearch/commit/e453dab)) -* **client:** remove algoliaClient, appId & apiKey ([#2338](https://github.com/algolia/react-instantsearch/issues/2338)) ([b84a0b5](https://github.com/algolia/react-instantsearch/commit/b84a0b5)) (use searchClient exclusively now) -* **context:** migrate to new React context ([#2178](https://github.com/algolia/react-instantsearch/issues/2178)) ([0a1abea](https://github.com/algolia/react-instantsearch/commit/0a1abea)), closes [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) -* **ssr:** update the SSR API ([#2555](https://github.com/algolia/react-instantsearch/issues/2555)) ([925bdb8](https://github.com/algolia/react-instantsearch/commit/925bdb8)), closes [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) - - -### BREAKING CHANGES - -* **searchClient:** argument is the only option now. - -Previously there were three options to pass a search client: searchClient, appId & apiKey, algoliaClient. The latter two have been removed, and now only `searchClient` is accepted. This searchClient is an instance of the `algoliasearch` module: - -```js -import algoliasearch from 'algoliasearch/lite'; - -const searchClient = algoliasearch( - 'myAppId', - 'myApiKey', - { _useRequestCache: true } -); - -// ... - -``` - -If you were relying on duplicate requests not being fired when using appId & apiKey before, you need to enable the `_useRequestCache` option now. - -* **SSR:** imports have changed - -In the server, you now directly import `findResultsState`, which now requires a `searchClient` in the second argument. - -In the App, you now use a regular `InstantSearch` component. - -* **Index & InstantSearch:** Remove `root` DOM element - -These elements now are pure containers for their children, and don't add a `div` to the DOM anymore. If you were relying on those for styling, wrap the `InstantSearch` and `Index` element with a `div` with an appropriate class. - -* **Index & InstantSearch:** Remove support for `root` prop - -Since these two arguments now no longer wrap their children in an element, they no longer accept a `root` prop. - -* **Highlight:** some paths will no longer be accepted - -We only accept paths separated with a dot or bracket now, like before. It's possible that a different type of path worked undocumented, but no longer does. - -* **algoliasearch-helper:** updating to the next major version - -This library is mostly internal, but it has had a major refactor (including removing lodash). This has no impact, unless you are dealing with it using `createConnector`. See the [migration guide](https://github.com/algolia/algoliasearch-helper-js/blob/next/documentation-src/metalsmith/content/upgrade.md) for the v3 of algoliasearch-helper for more information. - -# [5.7.0](https://github.com/algolia/react-instantsearch/compare/v5.6.0...v5.7.0) (2019-06-04) - - -### Bug Fixes - -* **highlight:** allow array as "attribute" ([#2474](https://github.com/algolia/react-instantsearch/issues/2474)) ([9dc829a](https://github.com/algolia/react-instantsearch/commit/9dc829a)), closes [#2461](https://github.com/algolia/react-instantsearch/issues/2461) -* **indexUtils:** allow index with dots in it ([#2350](https://github.com/algolia/react-instantsearch/issues/2350)) ([f91906f](https://github.com/algolia/react-instantsearch/commit/f91906f)) - - -### Features - -* **voiceSearch:** add voice search widget ([#2316](https://github.com/algolia/react-instantsearch/issues/2316)) ([0e3b124](https://github.com/algolia/react-instantsearch/commit/0e3b124)) - - - -# [5.6.0](https://github.com/algolia/react-instantsearch/compare/v5.5.0...v5.6.0) (2019-05-15) - - -### Bug Fixes - -* **connectQueryRules:** avoid to throw an error with undefined values ([#2436](https://github.com/algolia/react-instantsearch/issues/2436)) ([1e18287](https://github.com/algolia/react-instantsearch/commit/1e18287)) - - -### Features - -* **infiniteHits:** add previous button ([#2296](https://github.com/algolia/react-instantsearch/issues/2296)) ([010a69a](https://github.com/algolia/react-instantsearch/commit/010a69a)) - - - -# [5.5.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0...v5.5.0) (2019-04-23) - - -### Bug Fixes - -* **createInstantSearch:** change the User-Agent to use the new specs ([#2209](https://github.com/algolia/react-instantsearch/issues/2209)) ([642ba0b](https://github.com/algolia/react-instantsearch/commit/642ba0b)) - - -### Features - -* **DOMMaps:** expose withGoogleMaps HOC [PART-1] ([#2000](https://github.com/algolia/react-instantsearch/issues/2000)) ([2ae1dea](https://github.com/algolia/react-instantsearch/commit/2ae1dea)) -* **queryRules:** add Query Rules features ([#2286](https://github.com/algolia/react-instantsearch/issues/2286)) ([3ae9c01](https://github.com/algolia/react-instantsearch/commit/3ae9c01)) -* **insights:** add insights features ([#2215](https://github.com/algolia/react-instantsearch/pull/2215)) ([961e7a7](https://github.com/algolia/react-instantsearch/commit/961e7a7)) - - - -# [5.4.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.1...v5.4.0) (2019-02-05) - - -### Bug Fixes - -* **DOMMaps:** set React & React DOM as peer deps ([#1922](https://github.com/algolia/react-instantsearch/issues/1922)) ([2f2cefd](https://github.com/algolia/react-instantsearch/commit/2f2cefd)) - - - -# [5.4.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.0...v5.4.0-beta.1) (2019-01-10) - - -### Bug Fixes - -* **deps:** sync algoliasearch version ([#1879](https://github.com/algolia/react-instantsearch/issues/1879)) ([40f9c26](https://github.com/algolia/react-instantsearch/commit/40f9c26)) -* **maps:** use stable version for peer deps ([#1887](https://github.com/algolia/react-instantsearch/issues/1887)) ([9055167](https://github.com/algolia/react-instantsearch/commit/9055167)) - - - -# [5.4.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.3.2...v5.4.0-beta.0) (2019-01-08) - - -### Features - -* **Index:** introduce `indexId` prop ([#1833](https://github.com/algolia/react-instantsearch/issues/1833)) ([ec9e0fb](https://github.com/algolia/react-instantsearch/commit/ec9e0fb)) - - - - -## [5.3.2](https://github.com/algolia/react-instantsearch/compare/v5.3.1...v5.3.2) (2018-10-30) - - -### Bug Fixes - -* **sffv:** clamp maxFacetHits to the allowed range ([#1696](https://github.com/algolia/react-instantsearch/issues/1696)) ([83ce245](https://github.com/algolia/react-instantsearch/commit/83ce245)) - - - - -## [5.3.1](https://github.com/algolia/react-instantsearch/compare/v5.3.0...v5.3.1) (2018-09-26) - - -### Bug Fixes - -* **connector:** ensure canRefine is computed on the transformed items ([#1568](https://github.com/algolia/react-instantsearch/pull/1568)) ([c95384f](https://github.com/algolia/react-instantsearch/commit/c95384f)) -* **toggle:** ensure facet is present ([#1613](https://github.com/algolia/react-instantsearch/issues/1613)) ([e914ff6](https://github.com/algolia/react-instantsearch/commit/e914ff6)) - - - - -# [5.3.0](https://github.com/algolia/react-instantsearch/compare/v5.2.3...v5.3.0) (2018-09-24) - - -### Bug Fixes - -* **SSR:** bind getSearchParmaters to the component instance ([f34cb3d](https://github.com/algolia/react-instantsearch/commit/f34cb3d)) -* **GoogleMapsLoader:** pick google maps version ([#1540](https://github.com/algolia/react-instantsearch/issues/1540)) ([b14efcf](https://github.com/algolia/react-instantsearch/commit/b14efcf)) - - -### Features - -* **connectToggleRefinement:** implement canRefine & count ([#1588](https://github.com/algolia/react-instantsearch/issues/1588)) ([40672dd](https://github.com/algolia/react-instantsearch/commit/40672dd)) - - - - -## [5.2.3](https://github.com/algolia/react-instantsearch/compare/v5.2.2...v5.2.3) (2018-08-16) - - -### Bug Fixes - -* Allow object as type for Root (closes [#1446](https://github.com/algolia/react-instantsearch/issues/1446)) ([#1461](https://github.com/algolia/react-instantsearch/issues/1461)) ([7c2317b](https://github.com/algolia/react-instantsearch/commit/7c2317b)) -* **List:** render children list only when required ([#1472](https://github.com/algolia/react-instantsearch/issues/1472)) ([9eb2cbb](https://github.com/algolia/react-instantsearch/commit/9eb2cbb)), closes [#1459](https://github.com/algolia/react-instantsearch/issues/1459) - - - - -## [5.2.2](https://github.com/algolia/react-instantsearch/compare/v5.2.1...v5.2.2) (2018-07-16) - - -Publish the previous version on `stable`. - - - - -## [5.2.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0...v5.2.1) (2018-07-16) - - -### Bug Fixes - -* **GoogleMapsLoader:** inline the import to scriptjs ([#1427](https://github.com/algolia/react-instantsearch/issues/1427)) ([8019416](https://github.com/algolia/react-instantsearch/commit/8019416)) - - - - -# [5.2.0](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.2...v5.2.0) (2018-07-04) - - -### Bug Fixes - -* **translatable:** avoid create a new function on every render ([#1383](https://github.com/algolia/react-instantsearch/issues/1383)) ([1285b3b](https://github.com/algolia/react-instantsearch/commit/1285b3b)) - - -### Features - -* **core:** export translatable ([#1351](https://github.com/algolia/react-instantsearch/issues/1351)) ([6d5a89d](https://github.com/algolia/react-instantsearch/commit/6d5a89d)) -* **maps:** add connector & widget ([#1171](https://github.com/algolia/react-instantsearch/issues/1171)) ([16e288a](https://github.com/algolia/react-instantsearch/commit/16e288a)) - - - - -# [5.2.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.1...v5.2.0-beta.2) (2018-06-19) - - -### Features - -* export highlight tags from DOM / native ([#1342](https://github.com/algolia/react-instantsearch/issues/1342)) ([28a699e](https://github.com/algolia/react-instantsearch/commit/28a699e)) -* **createInstantSearch:** enable _useRequestCache ([#1346](https://github.com/algolia/react-instantsearch/issues/1346)) ([f772600](https://github.com/algolia/react-instantsearch/commit/f772600)) -* **dom:** export create class name ([#1348](https://github.com/algolia/react-instantsearch/issues/1348)) ([9017468](https://github.com/algolia/react-instantsearch/commit/9017468)) - - - - -# [5.2.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.0...v5.2.0-beta.1) (2018-06-04) - - -### Bug Fixes - -* **dom:** publish server file ([#1305](https://github.com/algolia/react-instantsearch/issues/1305)) ([bd79693](https://github.com/algolia/react-instantsearch/commit/bd79693)) - - - - -# [5.2.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.1.0...v5.2.0-beta.0) (2018-06-04) - - -This new version introduce a complete revamp of the package structure, but it should be completely transparent for the users. - -If you have any troubles with this version please open a issue on [Github](https://github.com/algolia/react-instantsearch/issues/new), thanks! - - - - -# [5.1.0](https://github.com/algolia/react-instantsearch/compare/v5.0.3...v5.1.0) (2018-05-28) - - -### Bug Fixes - -* **connectInfiniteHits:** always set a value for previous page ([#1195](https://github.com/algolia/react-instantsearch/issues/1195)) ([4c218d5](https://github.com/algolia/react-instantsearch/commit/4c218d5)) -* **indexUtils:** avoid throw an error on cleanUp multi indices ([#1265](https://github.com/algolia/react-instantsearch/issues/1265)) ([12f5ace](https://github.com/algolia/react-instantsearch/commit/12f5ace)) - - -### Features - -* **searchClient:** Add support for custom Search Clients ([#1216](https://github.com/algolia/react-instantsearch/issues/1216)) ([174cc28](https://github.com/algolia/react-instantsearch/commit/174cc28)) - - - - -## [5.0.3](https://github.com/algolia/react-instantsearch/compare/v5.0.2...v5.0.3) (2018-04-03) - - -### Bug Fixes - -* revert dependencies as devDependencies ([#1135](https://github.com/algolia/react-instantsearch/issues/1135)) ([6b627bb](https://github.com/algolia/react-instantsearch/commit/6b627bb)) - - - - -## [5.0.2](https://github.com/algolia/react-instantsearch/compare/v5.0.1...v5.0.2) (2018-04-03) - - -### Bug Fixes - -* use lodash version of unsupported Array.{fill, find} ([#1118](https://github.com/algolia/react-instantsearch/issues/1118)) ([ea7bf42](https://github.com/algolia/react-instantsearch/commit/ea7bf42)) - - - - -## [5.0.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0...v5.0.1) (2018-03-12) - - -### Bug Fixes - -* **connectInfiniteHits:** always provide an array for hits ([#1064](https://github.com/algolia/react-instantsearch/issues/1064)) ([c75e38b](https://github.com/algolia/react-instantsearch/commit/c75e38b)) - - - - -# [5.0.0](https://github.com/algolia/react-instantsearch/compare/v4.5.2...v5.0.0) (2018-03-06) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.5.2](https://github.com/algolia/react-instantsearch/compare/v4.5.1...v4.5.2) (2018-03-06) - - -### Bug Fixes - -* **connectRange:** update default refinement propTypes ([#978](https://github.com/algolia/react-instantsearch/issues/978)) ([c065fb1](https://github.com/algolia/react-instantsearch/commit/c065fb1)) -* **IndexUtils:** avoid throw an error when cleanUp multi index ([#1019](https://github.com/algolia/react-instantsearch/issues/1019)) ([865a3c3](https://github.com/algolia/react-instantsearch/commit/865a3c3)) -* **SearchBox:** avoid to bind click on reset button ([#979](https://github.com/algolia/react-instantsearch/issues/979)) ([ea3063a](https://github.com/algolia/react-instantsearch/commit/ea3063a)) - - - - -# [5.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2018-02-06) - - -Apply features & bug fixes from [v4.5.0](#450-2018-02-06) & [v4.5.1](#451-2018-02-06) on the v5. - -See their CHANGELOG for more details. - - - - -## [4.5.1](https://github.com/algolia/react-instantsearch/compare/v4.5.0...v4.5.1) (2018-02-06) - - -### Bug Fixes - -* **StarRating:** move to 1 based instead of 0 ([#949](https://github.com/algolia/react-instantsearch/issues/949)) ([eb0152d](https://github.com/algolia/react-instantsearch/commit/eb0152d)) - - - - -# [4.5.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v4.5.0) (2018-02-06) - - -### Bug Fixes - -* **connectRange:** use the same behaviour for currentRefinement in getMetadata ([#923](https://github.com/algolia/react-instantsearch/issues/923)) ([08917b6](https://github.com/algolia/react-instantsearch/commit/08917b6)) -* **connectToggle:** use currentRefinement in metadata instead of the label ([#909](https://github.com/algolia/react-instantsearch/issues/909)) ([89cae2b](https://github.com/algolia/react-instantsearch/commit/89cae2b)) -* **StarRatings:** always show the stars below ([#929](https://github.com/algolia/react-instantsearch/issues/929)) ([22bf93a](https://github.com/algolia/react-instantsearch/commit/22bf93a)) - - -### Features - -* **connectStateResults:** expose isSearchStalled ([#933](https://github.com/algolia/react-instantsearch/issues/933)) ([f45ba27](https://github.com/algolia/react-instantsearch/commit/f45ba27)) - - - -# [5.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v5.0.0-beta.0) (2018-01-30) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.4.2](https://github.com/algolia/react-instantsearch/compare/v4.4.1...v4.4.2) (2018-01-24) - - -### Bug Fixes - -* **currentRefinements:** give access to id and index from transformItems for deduplication ([#830](https://github.com/algolia/react-instantsearch/issues/830)) ([316b8f5](https://github.com/algolia/react-instantsearch/commit/316b8f5)) -* pass maxFacetHits to SFFV ([#863](https://github.com/algolia/react-instantsearch/issues/863)) ([de23a46](https://github.com/algolia/react-instantsearch/commit/de23a46)) - - - - -## [4.4.1](https://github.com/algolia/react-instantsearch/compare/v4.4.0...v4.4.1) (2018-01-09) - - -### Bug Fixes - -* **SearchBox**: clear SearchBox without search as you type ([#802](https://github.com/algolia/react-instantsearch/issues/802)) ([c49b2b6](https://github.com/algolia/react-instantsearch/commit/c49b2b6)) -* **connectRange:** check if facet exist before access ([#797](https://github.com/algolia/react-instantsearch/issues/797)) ([6520760](https://github.com/algolia/react-instantsearch/commit/6520760)) -* **stories:** avoid to use linear-background it breaks Argos every time ([#804](https://github.com/algolia/react-instantsearch/issues/804)) ([0beded7](https://github.com/algolia/react-instantsearch/commit/0beded7)) -* **stories:** limit hits per page on Index ([#806](https://github.com/algolia/react-instantsearch/issues/806)) ([6eb14d3](https://github.com/algolia/react-instantsearch/commit/6eb14d3)) - - -### Features - -* **Index:** allow custom root ([#792](https://github.com/algolia/react-instantsearch/issues/792)) ([d793b0a](https://github.com/algolia/react-instantsearch/commit/d793b0a)) - - - - -# [4.4.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0...v4.4.0) (2018-01-03) - - -### Bug Fixes - -* **createInstantSearch:** remove the client from the Snapshot ([#749](https://github.com/algolia/react-instantsearch/issues/749)) ([700d8f4](https://github.com/algolia/react-instantsearch/commit/700d8f4)) -* refresh cache memory leak example ([#784](https://github.com/algolia/react-instantsearch/issues/784)) ([cf228ac](https://github.com/algolia/react-instantsearch/commit/cf228ac)) -* **stories:** rename InstantSearch to `` ([#789](https://github.com/algolia/react-instantsearch/issues/789)) ([05efda5](https://github.com/algolia/react-instantsearch/commit/05efda5)) - - -### Features - -* InstantSearch root props ([#770](https://github.com/algolia/react-instantsearch/issues/770)) ([2d458f8](https://github.com/algolia/react-instantsearch/commit/2d458f8)) - - - - -# [4.3.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0-beta.0...v4.3.0) (2017-12-20) - - -### Bug Fixes - -* reset page with multi index ([#665](https://github.com/algolia/react-instantsearch/issues/665)) ([865b7dc](https://github.com/algolia/react-instantsearch/commit/865b7dc)) -* track all index in the manager ([#660](https://github.com/algolia/react-instantsearch/issues/660)) ([793502b](https://github.com/algolia/react-instantsearch/commit/793502b)) - - -### Features - -* **SearchBox:** provide a loading indicator ([#544](https://github.com/algolia/react-instantsearch/issues/544)) ([189659e](https://github.com/algolia/react-instantsearch/commit/189659e)) -* **Highlight:** support array of strings ([#715](https://github.com/algolia/react-instantsearch/issues/715)) ([8e93c6a](https://github.com/algolia/react-instantsearch/commit/8e93c6a)) - - - - -# [4.3.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.2.0...v4.3.0-beta.0) (2017-11-27) - - -### Bug Fixes - -* **babelrc:** add a key for each env development, production, es ([#547](https://github.com/algolia/react-instantsearch/issues/547)) ([fa9528d](https://github.com/algolia/react-instantsearch/commit/fa9528d)) -* **localizecount:** allow localized string for count in MenuSelect ([#657](https://github.com/algolia/react-instantsearch/issues/657)) ([67ebd34](https://github.com/algolia/react-instantsearch/commit/67ebd34)) -* **react-router-example:** Properly update search query when using browser navigation ([#604](https://github.com/algolia/react-instantsearch/issues/604)) ([9ee6600](https://github.com/algolia/react-instantsearch/commit/9ee6600)) - - -### Features - -* **refreshcache:** add prop refresh to InstantSearch instance ([#619](https://github.com/algolia/react-instantsearch/issues/619)) ([19f6de0](https://github.com/algolia/react-instantsearch/commit/19f6de0)) - - - - -# [4.2.0](https://github.com/algolia/react-instantsearch/compare/v4.1.3...v4.2.0) (2017-11-02) - - -### Bug Fixes - -* **connectRange:** handle boundaries on first call ([9f14dc0](https://github.com/algolia/react-instantsearch/commit/9f14dc0)) -* **connectRange:** use refine instead of cleanUp in metadata ([#526](https://github.com/algolia/react-instantsearch/issues/526)) ([1861235](https://github.com/algolia/react-instantsearch/commit/1861235)) -* **hierarchicaMenu:** allow sorting and using limit ([fe178ed](https://github.com/algolia/react-instantsearch/commit/fe178ed)), closes [#92](https://github.com/algolia/react-instantsearch/issues/92) -* **InfiniteHits:** add disabled style to the LoadMore button ([#477](https://github.com/algolia/react-instantsearch/issues/477)) ([faba1ad](https://github.com/algolia/react-instantsearch/commit/faba1ad)) -* **Range:** handle float, allow reset and respect boundaries ([75969b8](https://github.com/algolia/react-instantsearch/commit/75969b8)) -* **RangeInput:** fix compatibility with React 16 & Panel ([3f218db](https://github.com/algolia/react-instantsearch/commit/3f218db)) -* **searchbox:** add maxlength 512 ([#542](https://github.com/algolia/react-instantsearch/issues/542)) ([5bd4033](https://github.com/algolia/react-instantsearch/commit/5bd4033)), closes [#510](https://github.com/algolia/react-instantsearch/issues/510) - - -### Features - -* **MenuSelect:** add component and connector ([cc6e0d7](https://github.com/algolia/react-instantsearch/commit/cc6e0d7)) - - - - -## [4.1.3](https://github.com/algolia/react-instantsearch/compare/v4.1.2...v4.1.3) (2017-10-09) - - -### Bug Fixes - -* **List:** remove React16 warning ([#442](https://github.com/algolia/react-instantsearch/issues/442)) ([8d6cf18](https://github.com/algolia/react-instantsearch/commit/8d6cf18)) - - -### Features - -* **connectStateResults:** add component props ([#434](https://github.com/algolia/react-instantsearch/issues/434)) ([c629b97](https://github.com/algolia/react-instantsearch/commit/c629b97)) - - - - -## [4.1.2](https://github.com/algolia/react-instantsearch/compare/v4.1.1...v4.1.2) (2017-09-26) - - -### Features - -* **Conditional:** add connectStateResults connector ([#357](https://github.com/algolia/react-instantsearch/issues/357)) ([462df5f](https://github.com/algolia/react-instantsearch/commit/462df5f)) - - - - -## [4.1.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0...v4.1.1) (2017-09-13) - - -### Bug Fixes - -* **MultiIndex:** reset page to 1 when share widgets refine (#312) ([c85a7bf](https://github.com/algolia/react-instantsearch/commit/c85a7bf)) -* **MultiIndex:** Trigger new search when `` props are updated (#318) ([bb11965](https://github.com/algolia/react-instantsearch/commit/bb11965)) - - - - -# [4.1.0](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.5...v4.1.0) (2017-08-28) - - -### Bug Fixes - -* **Highlighting:** revert breaking change (#245) ([045ee06](https://github.com/algolia/react-instantsearch/commit/045ee06)) -* **List:** adds support for any type of renderable element (#266) ([d848bb6](https://github.com/algolia/react-instantsearch/commit/d848bb6)) -* **Pagination:** fixed the offset ([3c0fff2](https://github.com/algolia/react-instantsearch/commit/3c0fff2)) -* **PoweredBy:** aria-* tags are not camelcased (#261) ([dc4a5bb](https://github.com/algolia/react-instantsearch/commit/dc4a5bb)) - - - - -# [4.1.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2017-08-08) - - -### Bug Fixes - -* **SSR:** clean SP before rendering agan (#238) ([e765886](https://github.com/algolia/react-instantsearch/commit/e765886)) - - -### Features - -* **Breadcrumb:** add a new widget & connector (#228) ([7f8f3ae](https://github.com/algolia/react-instantsearch/commit/7f8f3ae)) - - - - -# [4.1.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2017-08-03) - - -### Bug Fixes - -* **deps:** Update dependency lint-staged to version ^4.0.0 (#201) ([6867a1b](https://github.com/algolia/react-instantsearch/commit/6867a1b)) -* **nextjs/ssr:** parse `params.asPath` (#189) ([ae17da0](https://github.com/algolia/react-instantsearch/commit/ae17da0)) -* **PoweredBy:** add a label to the Algolia logo (#216) ([cd235bd](https://github.com/algolia/react-instantsearch/commit/cd235bd)) -* **react:** remove typo around `"" 2` (#220) ([f73eb04](https://github.com/algolia/react-instantsearch/commit/f73eb04)) -* **ScrollTo:** scroll to only if change triggered by the widget observed (#202) ([2d76022](https://github.com/algolia/react-instantsearch/commit/2d76022)) -* **theme:** format the count of items appearing in a refinement (#217) ([2225c24](https://github.com/algolia/react-instantsearch/commit/2225c24)) - - - - -# [4.1.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2017-07-25) - - -### Bug Fixes - -* **error:** reset error when receiving results of a query (not when sending it) (#179) ([bb12c29](https://github.com/algolia/react-instantsearch/commit/bb12c29)) -* **highlight:** wrong parsing between client and server (#183) ([2daae70](https://github.com/algolia/react-instantsearch/commit/2daae70)) -* **poweredBy:** SSR compatibility (#181) ([ec0fa8a](https://github.com/algolia/react-instantsearch/commit/ec0fa8a)) - - -### BREAKING CHANGES - -* **highlight:** We remove the timestamp present in our highlight preTag and postTag. If you were using regex to parse the -highlighting results then you'll need to adapt it as now it's only "ais-highlight". - - - - -# [4.1.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2017-07-20) - - -### Bug Fixes - -* **error:** reset error if next query is successful (#175) ([ff50a07](https://github.com/algolia/react-instantsearch/commit/ff50a07)) - - - - -# [4.1.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2017-07-12) - - - - -# [4.1.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.0.7...v4.1.0-beta.0) (2017-07-10) - - -### Bug Fixes - -* **argos:** address flakyness (#152) ([84ef8f1](https://github.com/algolia/react-instantsearch/commit/84ef8f1)) - - -### Features - -* **server-side rendering:** Add API features for server-side rendering ([86b14d1](https://github.com/algolia/react-instantsearch/commit/86b14d1)) - - - - -## [4.0.7](https://github.com/algolia/react-instantsearch/compare/v4.0.6...v4.0.7) (2017-07-06) - - -### Bug Fixes - -* **results:** revert commit that ensure hits are returned only if right indices (#149) ([df9aa25](https://github.com/algolia/react-instantsearch/commit/df9aa25)) - - - - -## [4.0.6](https://github.com/algolia/react-instantsearch/compare/v4.0.5...v4.0.6) (2017-06-29) - - -### Bug Fixes - -* **store:** delay call to listener to prevent infinite loops (#143) ([0945958](https://github.com/algolia/react-instantsearch/commit/0945958)) - - - - -## [4.0.5](https://github.com/algolia/react-instantsearch/compare/v4.0.4...v4.0.5) (2017-06-26) - - -### Bug Fixes - -* **MultiIndex:** ensure getResults return only hits matching index in the context (#136) ([124ffe6](https://github.com/algolia/react-instantsearch/commit/124ffe6)) -* **MultiIndex:** handle if namespace isn't in search state (#139) ([1aab324](https://github.com/algolia/react-instantsearch/commit/1aab324)) -* **storybook:** process CSS through autoprefixer (#138) ([62cf512](https://github.com/algolia/react-instantsearch/commit/62cf512)) - - - - -## [4.0.4](https://github.com/algolia/react-instantsearch/compare/v4.0.3...v4.0.4) (2017-06-19) - - -### Bug Fixes - -* **MultiIndex:** handle switch between mono and multi index (#132) ([e161921](https://github.com/algolia/react-instantsearch/commit/e161921)) - - - - -## [4.0.3](https://github.com/algolia/react-instantsearch/compare/v4.0.2...v4.0.3) (2017-06-14) - - -### Bug Fixes - -* **SFFV:** search status we're not inside search state (#125) ([5f3e670](https://github.com/algolia/react-instantsearch/commit/5f3e670)) - - - - -## [4.0.2](https://github.com/algolia/react-instantsearch/compare/v4.0.1...v4.0.2) (2017-05-30) - - - - -## [4.0.1](https://github.com/algolia/react-instantsearch/compare/v4.0.0...v4.0.1) (2017-05-17) - - -### Bug Fixes - -* **state:** nested attributes for faceting were not handled ([11bd122](https://github.com/algolia/react-instantsearch/commit/11bd122)) - - - - -# [4.0.0](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.6...v4.0.0) (2017-05-15) - -### Features and migration guide - -You can find all the details of the release and the migration guide from v3 to v4 here: https://discourse.algolia.com/t/react-instantsearch-v4/1329. - - - -# [4.0.0-beta.6](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2017-05-04) - - - - -# [4.0.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2017-05-02) - - -### Bug Fixes - -* **connectAutoComplete:** allow usage with hits from a single index (#75) ([8b3b358](https://github.com/algolia/react-instantsearch/commit/8b3b358)), closes [#74](https://github.com/algolia/react-instantsearch/issues/74) -* **InstantSearch:** update algoliaClient when it change (#70) ([9e97dbd](https://github.com/algolia/react-instantsearch/commit/9e97dbd)) - - - - -# [4.0.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2017-04-25) - - -### Bug Fixes - -* **MultIndex:** no need to nest hits, if those are from main index. (#56) ([86e0bd7](https://github.com/algolia/react-instantsearch/commit/86e0bd7)) - - -### Features - -* **MultiIndex:** remove the need for virtual hits when using connectAutoComplete (#45) ([7549019](https://github.com/algolia/react-instantsearch/commit/7549019)) - - - - -# [4.0.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2017-04-21) - - -### Bug Fixes - -* replace usage of Object.values (#47) ([4c79e3e](https://github.com/algolia/react-instantsearch/commit/4c79e3e)) - - - - -# [4.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2017-04-18) - - -### Bug Fixes - -* **InstantSearch:** dont fire request/onsearchStateChange when unmounting (#26) ([9a1487a](https://github.com/algolia/react-instantsearch/commit/9a1487a)) -* **MultiIndex:** derived helper were using main index specifics params (#36) ([991fea6](https://github.com/algolia/react-instantsearch/commit/991fea6)) -* **MultiIndex:** revert breaking change if no multiple index (#32) ([44f7de0](https://github.com/algolia/react-instantsearch/commit/44f7de0)) -* **util:** remove empty key was removing non object key (#29) ([9f795c7](https://github.com/algolia/react-instantsearch/commit/9f795c7)) - - -### Features - -* **Highlighter:** allow rendering to custom tag (#11) ([52a1212](https://github.com/algolia/react-instantsearch/commit/52a1212)) -* **SearchBox:** add default width and height to buttons. (#34) ([bcabf9b](https://github.com/algolia/react-instantsearch/commit/bcabf9b)) - - - - -# [4.0.0-beta.1](https://github.com/algolia/instantsearch.js/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2017-04-03) - - -### Bug Fixes - -* **SFFV:** fix wrong query behaviour with slow network (#2086) ([c251e8f](https://github.com/algolia/instantsearch.js/commit/c251e8f)), closes [#2086](https://github.com/algolia/instantsearch.js/issues/2086) - - - - -# [4.0.0-beta.0](https://github.com/algolia/instantsearch.js/compare/v3.3.0...v4.0.0-beta.0) (2017-03-28) - - -### Features - -* **multi-index:** ease multi index and auto complete ([09a4e1d](https://github.com/algolia/instantsearch.js/commit/09a4e1d)) - - -### BREAKING CHANGES - -* multi-index: * Reseting the pagination should be done at each connector level inside the "refine" function when returning the search state. -* The current page now appears inside the search state when a widget is used -* Query values are part of the items prop of the connectCurrentRefinements connector. Behaviour is unchanged, query will be filtered if clearsQuery prop is false. -* Add the index name to all the current refinements items. (not used by our widgets yet, but available if needed). - - - - -# [3.3.0](https://github.com/algolia/instantsearch.js/compare/v3.2.2-beta0...v3.3.0) (2017-03-22) - - -### Bug Fixes - -* **example:** Fix access to props in react-router example ([1417d6f](https://github.com/algolia/instantsearch.js/commit/1417d6f)) - - - - -## [3.2.2-beta0](https://github.com/algolia/instantsearch.js/compare/v3.2.1...v3.2.2-beta0) (2017-03-20) - - -### Bug Fixes - -* **InfiniteHits:** provide translation key for `Load More` (#2048) ([6130bf2](https://github.com/algolia/instantsearch.js/commit/6130bf2)) -* **SearchBox:** better mobile behaviour by default ([ea968b3](https://github.com/algolia/instantsearch.js/commit/ea968b3)) -* **example:** link to instantsearch/react (#2007) ([5e674cd](https://github.com/algolia/instantsearch.js/commit/5e674cd)) -* **recipes:** react router v4 ([de673bf](https://github.com/algolia/instantsearch.js/commit/de673bf)) - - -### Features - -* **SearchBox:** add role=search to the form (#2046) ([d1e90f3](https://github.com/algolia/instantsearch.js/commit/d1e90f3)) -* **SearchBox:** allow custom reset and submit components (#1991) ([cd303d7](https://github.com/algolia/instantsearch.js/commit/cd303d7)) -* **searchBox:** add event handling ([e267ab6](https://github.com/algolia/instantsearch.js/commit/e267ab6)), closes [#2017](https://github.com/algolia/instantsearch.js/issues/2017) - - - - -## [3.2.1](https://github.com/algolia/instantsearch.js/compare/v3.2.0...v3.2.1) (2017-02-22) - - -### Bug Fixes - -* **umd:** Add connectors to UMD build (#1988) ([23ac5e6](https://github.com/algolia/instantsearch.js/commit/23ac5e6)), closes [#1987](https://github.com/algolia/instantsearch.js/issues/1987) - - - - -# [3.2.0](https://github.com/algolia/instantsearch.js/compare/v3.1.0...v3.2.0) (2017-02-15) - - -### Bug Fixes - -* **Configure:** use props a unique source of truth (#1967) ([9d53d86](https://github.com/algolia/instantsearch.js/commit/9d53d86)) -* **SearchBox:** Safari can only have with xlinkHref (#1970) ([7ab00bd](https://github.com/algolia/instantsearch.js/commit/7ab00bd)), closes [#1968](https://github.com/algolia/instantsearch.js/issues/1968) - - -### Features - -* **MultiRange:** add an all range (#1959) ([a3dc950](https://github.com/algolia/instantsearch.js/commit/a3dc950)) - - -### BREAKING CHANGES - -* MultiRange: - MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system. - - - - -# [3.1.0](https://github.com/algolia/instantsearch.js/compare/v3.0.0...v3.1.0) (2017-02-08) - - -### Bug Fixes - -* **Configure:** call onSearchStateChange when props are updated (#1953) ([7e151db](https://github.com/algolia/instantsearch.js/commit/7e151db)), closes [#1950](https://github.com/algolia/instantsearch.js/issues/1950) -* **Configure:** trigger onSearchStateChange with the right data ([11e5af8](https://github.com/algolia/instantsearch.js/commit/11e5af8)) -* **createConnector:** updates with latest props on state change (#1951) ([cd3a82c](https://github.com/algolia/instantsearch.js/commit/cd3a82c)) - - -### Features - -* **ClearAll:** add withQuery to also clear the search query (#1958) ([c0e695b](https://github.com/algolia/instantsearch.js/commit/c0e695b)) - - - - -# [3.0.0](https://github.com/algolia/instantsearch.js/compare/v2.2.5...v3.0.0) (2017-02-06) - - -### Bug Fixes - -* ***List:** disable shortcuts in *List SearchBoxes (#1921) ([51a76ae](https://github.com/algolia/instantsearch.js/commit/51a76ae)), closes [#1920](https://github.com/algolia/instantsearch.js/issues/1920) -* **Configure:** add configure parameters in search state (#1935) ([0971330](https://github.com/algolia/instantsearch.js/commit/0971330)), closes [#1863](https://github.com/algolia/instantsearch.js/issues/1863) -* **Hits:** limit the hitComponent to be only a function (#1912) ([b3c9578](https://github.com/algolia/instantsearch.js/commit/b3c9578)) -* **Pagination:** fix and indicate when pagination is disabled ([5f20199](https://github.com/algolia/instantsearch.js/commit/5f20199)), closes [#1938](https://github.com/algolia/instantsearch.js/issues/1938) -* **StarRating:** usage with filters (#1933) ([667e9d5](https://github.com/algolia/instantsearch.js/commit/667e9d5)) -* **withSearchBox:** keep displaying searchBox when no items found (#1930) ([30de4cd](https://github.com/algolia/instantsearch.js/commit/30de4cd)) - - -### Features - -* **MultiRange:** indicate if a range has no refinements (#1926) ([80b6450](https://github.com/algolia/instantsearch.js/commit/80b6450)) -* **panel:** add a panel widget (#1889) ([594e1a1](https://github.com/algolia/instantsearch.js/commit/594e1a1)) -* **starRating:** indicate when any refinement has no effect ([c547ae5](https://github.com/algolia/instantsearch.js/commit/c547ae5)) -* **widgets:** default design for disabled states (#1929) ([31f010b](https://github.com/algolia/instantsearch.js/commit/31f010b)) - -### Migration guide - -The migration to V3.0.0 should be safe and you should do it. - -There are two breaking changes that you will need to handle in your codebase: -- Anytime you are using a connector, when there are no more items in it or no more hits, we will still call your Component. Thus you will have to handle cases like dealing with empty arrays and decide if you want to unmount or hide the widget. -- Anytime you are using a widget, when there are no more items in it or no more hits, we will still display the widget. You can then decide to hide it with CSS. - - -## [2.2.5](https://github.com/algolia/instantsearch.js/compare/v2.2.4...v2.2.5) (2017-01-23) - - -### Bug Fixes - -* **currentRefinements:** make removing a toggle refinement work ([8995e64](https://github.com/algolia/instantsearch.js/commit/8995e64)) - - - - -## [2.2.4](https://github.com/algolia/instantsearch.js/compare/v2.2.3...v2.2.4) (2017-01-20) - - -### Bug Fixes - -* **publish:** publish react-instantsearch/dist instead of root (#1884) ([64414e0](https://github.com/algolia/instantsearch.js/commit/64414e0)) - - - - -## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-01-20) - - -### Bug Fixes - -* **SFFV:** translations for searchbox were not applied (#1879) ([e9b4ee1](https://github.com/algolia/instantsearch.js/commit/e9b4ee1)) - - - - -## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-01-18) - - -### Bug Fixes - -* **react-router:** search was triggered two many times (#1840) ([25e9db5](https://github.com/algolia/instantsearch.js/commit/25e9db5)) -* **SFFV:** empty query triggered a new SFFV (#1875) ([6c8259a](https://github.com/algolia/instantsearch.js/commit/6c8259a)) - - - - -## [2.2.1](https://github.com/algolia/instantsearch.js/compare/v2.2.0...v2.2.1) (2017-01-18) - - -### Bug Fixes - -* **createInstantsearch:** fix missing props (#1867) ([8d319b5](https://github.com/algolia/instantsearch.js/commit/8d319b5)), closes [#1867](https://github.com/algolia/instantsearch.js/issues/1867) - - - - -# [2.2.0](https://github.com/algolia/instantsearch.js/compare/v2.1.0...v2.2.0) (2017-01-17) - - -### Bug Fixes - -* **clear:** clearing wasn't working with too+ same type facets selected (#1820) ([a9a2364](https://github.com/algolia/instantsearch.js/commit/a9a2364)) -* **connectSearchBox:** handle `defaultRefinement` (#1829) ([7a730e2](https://github.com/algolia/instantsearch.js/commit/7a730e2)), closes [#1826](https://github.com/algolia/instantsearch.js/issues/1826) -* **Instantsearch:** Update all props on InstantSearch (#1828) ([2ed9b49](https://github.com/algolia/instantsearch.js/commit/2ed9b49)) -* **InstantSearch:** add specific `react-instantsearch ${version}` agent (#1844) ([a1113bc](https://github.com/algolia/instantsearch.js/commit/a1113bc)) -* **SFFV:** correct propTypes and add missing default values (#1845) ([a4c1b31](https://github.com/algolia/instantsearch.js/commit/a4c1b31)) -* **test:** add missing Snippet and Highliter snapshot ([4accce5](https://github.com/algolia/instantsearch.js/commit/4accce5)) -* **widgets:** replace setImmediate use with Promise use when update is needed (#1811) ([17e2497](https://github.com/algolia/instantsearch.js/commit/17e2497)) - - -### Features - -* **Menu, connectMenu:** add search for facet values (#1822) ([a6c513e](https://github.com/algolia/instantsearch.js/commit/a6c513e)) -* **snippet:** add a snippet widget to be able to highlight snippet results (#1797) ([2aecc40](https://github.com/algolia/instantsearch.js/commit/2aecc40)) -* **widgets:** add transformItems to be able to sort and filter (#1809) ([ba539f0](https://github.com/algolia/instantsearch.js/commit/ba539f0)) - - - - -# [2.1.0](https://github.com/algolia/instantsearch.js/compare/v2.0.1...v2.1.0) (2017-01-04) - - -### Bug Fixes - -* **createInstantSearchManager:** drop outdated response (#1765) ([76c5312](https://github.com/algolia/instantsearch.js/commit/76c5312)) -* **highlight:** highlight should work even if the attribute is missing (#1791) ([5b79b15](https://github.com/algolia/instantsearch.js/commit/5b79b15)), closes [#1790](https://github.com/algolia/instantsearch.js/issues/1790) -* **InfiniteHits:** better classname to loadmore btn (#1789) ([ad2ded3](https://github.com/algolia/instantsearch.js/commit/ad2ded3)) -* **starRatings:** click on selected range doesn't unselect it (#1766) ([beacc72](https://github.com/algolia/instantsearch.js/commit/beacc72)) -* **website:** broken demo links (#1802) ([0abe2f5](https://github.com/algolia/instantsearch.js/commit/0abe2f5)) -* **widgets:** add 300px width for the default SearchBox (#1803) ([bf5d791](https://github.com/algolia/instantsearch.js/commit/bf5d791)) - - -### Features - -* **InfiniteHits:** Add class to load more button (#1787) ([416febd](https://github.com/algolia/instantsearch.js/commit/416febd)) -* **RefinementList, connectRefinementList:** allow to search for facet values ([e086a81](https://github.com/algolia/instantsearch.js/commit/e086a81)) - - - - -## [2.0.1](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.1) (2016-12-15) - - -### Bug Fixes - -* **connectRange:** when unfinite numbers are passed throw ([75bec0d](https://github.com/algolia/instantsearch.js/commit/75bec0d)) -* **react-native:** use View as a container for react-native (#1729) ([5b76f75](https://github.com/algolia/instantsearch.js/commit/5b76f75)), closes [#1730](https://github.com/algolia/instantsearch.js/issues/1730) -* **SearchBox:** autocomplete was not disabled by default (#1742) ([bc76618](https://github.com/algolia/instantsearch.js/commit/bc76618)) -* **starRating:** call createURL with the right interface (min/max) (#1747) ([f9ab9b6](https://github.com/algolia/instantsearch.js/commit/f9ab9b6)) - - - - -## [2.0.0](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.0) (2016-12-08) - -First release of `react-instantsearch` diff --git a/packages/react-instantsearch-hooks-server/README.md b/packages/react-instantsearch-hooks-server/README.md deleted file mode 100644 index a2c754b298..0000000000 --- a/packages/react-instantsearch-hooks-server/README.md +++ /dev/null @@ -1,74 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [react-instantsearch-hooks-server](#react-instantsearch-hooks-server) - - [Installation](#installation) - - [Getting started](#getting-started) - - [API reference](#api-reference) - - [Documentation](#documentation) - - [Contributing](#contributing) - - [License](#license) - - - -# react-instantsearch-hooks-server - -React InstantSearch Hooks is an open-source, **UI library** for React that lets you server-side render a search interface. - -Server-side rendering (SSR) lets you generate HTML from InstantSearch components on the server. React InstantSearch Hooks is compatible with server-side rendering. The library provides an API that works with any SSR solution. - -## Installation - -React InstantSearch Hooks Server is available on the npm registry. - -```sh -yarn add react-instantsearch-hooks-server -# or -npm install react-instantsearch-hooks-server -``` - -## Getting started - -React InstantSearch Hooks is compatible with server-side rendering. The library provides an API that works with any SSR solution. You can, for example, use it with an [express](https://expressjs.com/) server or with [Next.js](https://nextjs.org/). - -Check out our [**Server-side rendering guide**](https://algolia.com/doc/guides/building-search-ui/going-further/server-side-rendering/react-hooks/) to start rendering your React InstantSearch Hooks app on the server. - -## API reference - -- [`getServerState()`](https://algolia.com/doc/api-reference/widgets/server-state/react-hooks/) -- [``](https://algolia.com/doc/api-reference/widgets/ssr-provider/react-hooks/) - -## Documentation - -The full documentation is available on [algolia.com/doc](https://algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/). - -## Contributing - -We welcome all contributors, from casual to regular 💙 - -- **Bug report**. Is something not working as expected? [Send a bug report][contributing-bugreport]. -- **Feature request**. Would you like to add something to the library? [Send a feature request][contributing-featurerequest]. -- **Documentation**. Did you find a typo in the doc? [Open an issue][contributing-newissue] and we'll take care of it. -- **Development**. If you don't know where to start, you can check the open issues that are [tagged easy][contributing-label-easy], the [bugs][contributing-label-bug] or [chores][contributing-label-chore]. - -To start contributing to code, you need to: - -1. [Fork the project](https://help.github.com/articles/fork-a-repo/) -1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) -1. Install the dependencies: `yarn` - -Please read [our contribution process](https://github.com/algolia/instantsearch.js/blob/master/CONTRIBUTING.md) to learn more. - -## License - -React InstantSearch Hooks is [MIT licensed](../../LICENSE). - - - -[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch+Hooks&title=Feature%20request%3A%20 -[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 diff --git a/packages/react-instantsearch-hooks-server/package.json b/packages/react-instantsearch-hooks-server/package.json deleted file mode 100644 index c4c0f18f5a..0000000000 --- a/packages/react-instantsearch-hooks-server/package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "react-instantsearch-hooks-server", - "version": "6.47.3", - "description": "⚡ Server-side support for React InstantSearch Hooks, by Algolia", - "source": "src/index.ts", - "types": "dist/es/index.d.ts", - "main": "dist/cjs/index.js", - "module": "dist/es/index.js", - "type": "module", - "exports": { - ".": { - "import": "./dist/es/index.js", - "require": "./dist/cjs/index.js" - } - }, - "sideEffects": false, - "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/", - "repository": { - "type": "git", - "url": "https://github.com/algolia/instantsearch.js" - }, - "author": { - "name": "Algolia, Inc.", - "url": "https://www.algolia.com" - }, - "keywords": [ - "algolia", - "components", - "fast", - "instantsearch", - "react", - "search" - ], - "files": [ - "README.md", - "dist" - ], - "scripts": { - "clean": "rm -rf dist", - "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es && yarn build:types", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet && ../../scripts/prepare-cjs.sh", - "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", - "test:exports": "node ./test/module/is-es-module.mjs && node ./test/module/is-cjs-module.cjs" - }, - "dependencies": { - "@babel/runtime": "^7.1.2", - "instantsearch.js": "4.56.8", - "react-instantsearch-hooks": "6.47.3" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19", - "react-dom": ">= 16.8.0 < 19" - } -} diff --git a/packages/react-instantsearch-hooks-server/test/module/is-cjs-module.cjs b/packages/react-instantsearch-hooks-server/test/module/is-cjs-module.cjs deleted file mode 100644 index e3718e6fee..0000000000 --- a/packages/react-instantsearch-hooks-server/test/module/is-cjs-module.cjs +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable no-console */ - -const assert = require('assert'); - -const ReactInstantSearchHooksServer = require('react-instantsearch-hooks-server'); - -assert.ok(ReactInstantSearchHooksServer); - -console.log('react-instantsearch-hooks-server is valid CJS'); diff --git a/packages/react-instantsearch-hooks-server/test/module/is-es-module.mjs b/packages/react-instantsearch-hooks-server/test/module/is-es-module.mjs deleted file mode 100644 index 943c653199..0000000000 --- a/packages/react-instantsearch-hooks-server/test/module/is-es-module.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable no-console */ -import assert from 'assert'; - -import * as ReactInstantSearchHooksServer from 'react-instantsearch-hooks-server'; - -assert.ok(ReactInstantSearchHooksServer); - -console.log('react-instantsearch-hooks-server is valid ESM'); diff --git a/packages/react-instantsearch-hooks-web/CHANGELOG.md b/packages/react-instantsearch-hooks-web/CHANGELOG.md deleted file mode 100644 index 2b4129ab53..0000000000 --- a/packages/react-instantsearch-hooks-web/CHANGELOG.md +++ /dev/null @@ -1,2042 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.47.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.2...react-instantsearch-hooks-web@6.47.3) (2023-07-27) - - -### Bug Fixes - -* add a future warning when the package name changes ([#5778](https://github.com/algolia/instantsearch.js/issues/5778)) ([3d22ee4](https://github.com/algolia/instantsearch.js/commit/3d22ee45e1f03a443323a371621262f1fe45e664)) - - - - - -## [6.47.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.1...react-instantsearch-hooks-web@6.47.2) (2023-07-25) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.47.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.0...react-instantsearch-hooks-web@6.47.1) (2023-07-19) - - -### Bug Fixes - -* **instantsearch:** keep algoliasearch-helper as external dependency during build ([#5765](https://github.com/algolia/instantsearch.js/issues/5765)) ([550fefa](https://github.com/algolia/instantsearch.js/commit/550fefa1401773f38dedc20322513ae662faa25d)) - - - - - -# [6.47.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.46.0...react-instantsearch-hooks-web@6.47.0) (2023-07-18) - - -### Features - -* **react-instantsearch-hooks web:** rename `` translation ([#5756](https://github.com/algolia/instantsearch.js/issues/5756)) ([6c70035](https://github.com/algolia/instantsearch.js/commit/6c700350377d69a71b8ed44f70952d33ed81d085)) - - - - - -## [6.46.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.45.1...react-instantsearch-hooks-web@6.46.0) (2023-07-10) - - -### Bug Fixes - -* **url:** base createURL on UiState instead of SearchParameters ([#5696](https://github.com/algolia/instantsearch.js/issues/5696)) ([7e2c8a2](https://github.com/algolia/instantsearch.js/commit/7e2c8a295a6fc5ba36d9482f645ef55b422d5e75)), closes [#5694](https://github.com/algolia/instantsearch.js/issues/5694) - - - - - -## [6.45.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.45.0...react-instantsearch-hooks-web@6.45.1) (2023-07-04) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.45.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.3...react-instantsearch-hooks-web@6.45.0) (2023-06-20) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.44.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.2...react-instantsearch-hooks-web@6.44.3) (2023-06-13) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.44.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.1...react-instantsearch-hooks-web@6.44.2) (2023-06-05) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.44.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.0...react-instantsearch-hooks-web@6.44.1) (2023-05-30) - - -### Bug Fixes - -* **insights:** send default click event when using auxiliary pointer button ([#5634](https://github.com/algolia/instantsearch.js/issues/5634)) ([7e4a216](https://github.com/algolia/instantsearch.js/commit/7e4a2162f87596a384b35c97efa51db9bb6f8973)) - - - - - -## [6.43.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.43.0...react-instantsearch-hooks-web@6.43.1) (2023-05-16) - - -### Bug Fixes - -* **rangeinput:** allow input of numbers with precision ([#5541](https://github.com/algolia/instantsearch.js/issues/5541)) ([fb48951](https://github.com/algolia/instantsearch.js/commit/fb489513a8550528f3e2867be30fb380229ad188)) -* **this:** ensure all functions are able to be destructured ([#5611](https://github.com/algolia/instantsearch.js/issues/5611)) ([a8b5c1e](https://github.com/algolia/instantsearch.js/commit/a8b5c1e5bbd6afac39fce523f7d7c2ec02f51153)), closes [#5589](https://github.com/algolia/instantsearch.js/issues/5589) - - - - - -# [6.43.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.2...react-instantsearch-hooks-web@6.43.0) (2023-04-24) - - -### Bug Fixes - -* **lifecycle:** prevent extra network requests when unmounting multiple widgets ([#5602](https://github.com/algolia/instantsearch.js/issues/5602)) ([11458ee](https://github.com/algolia/instantsearch.js/commit/11458eee7e7f0f3e9c5f368584a16f58646b1cdd)) - - -### Features - - -* **insights:** add insights option to InstantSearch ([#5488](https://github.com/algolia/instantsearch.js/issues/5488)) ([9031573](https://github.com/algolia/instantsearch.js/commit/9031573807fa6803dcfae9f33d61b8f111f68423)) ([#5578](https://github.com/algolia/instantsearch.js/issues/5578)) ([8fb517f](https://github.com/algolia/instantsearch.js/commit/8fb517f15381ecb32ea00cf4b01a0fd5e70e1d17)) ([#5545](https://github.com/algolia/instantsearch.js/issues/5545)) ([99a0972](https://github.com/algolia/instantsearch.js/commit/99a0972663b8f3284cac3b5621571ced7a33908f)) ([#5493](https://github.com/algolia/instantsearch.js/issues/5493)) ([cff723f](https://github.com/algolia/instantsearch.js/commit/cff723fc95a90ebb2ed14c46c51ab05764835a47)) -* **insights:** always pass Algolia credentials locally ([#5554](https://github.com/algolia/instantsearch.js/issues/5554)) ([654ab81](https://github.com/algolia/instantsearch.js/commit/654ab81e1669354c249710b6756610fba35d54b4)) ([#5558](https://github.com/algolia/instantsearch.js/issues/5558)) ([82144c0](https://github.com/algolia/instantsearch.js/commit/82144c0a0b18e6b47d6f508e5c670a9de274c121)) ([#5529](https://github.com/algolia/instantsearch.js/issues/5529)) ([8537f8f](https://github.com/algolia/instantsearch.js/commit/8537f8f7a10bcaf053ff62180c082e077b1b052d)) -* **insights:** annotate events with algoliaSource ([#5580](https://github.com/algolia/instantsearch.js/issues/5580)) ([c419307](https://github.com/algolia/instantsearch.js/commit/c419307a5f7fe46d5032c9437a17c8e3dad57fe5)) -* **insights:** automatically load search-insights if not passed ([#5484](https://github.com/algolia/instantsearch.js/issues/5484)) ([a85797b](https://github.com/algolia/instantsearch.js/commit/a85797b503edc94e001c5bfb3b754db6cb556943)) -* **insights:** enable default click events on hits and infinite hits ([#5522](https://github.com/algolia/instantsearch.js/issues/5522)) ([271bd12](https://github.com/algolia/instantsearch.js/commit/271bd12e34bc55656976bb53c90282193083eb86)) ([#5527](https://github.com/algolia/instantsearch.js/issues/5527)) ([0e55821](https://github.com/algolia/instantsearch.js/commit/0e558213c807cd17d592fadec052f3d1fc692e6c)) -* **insights:** prevent potential errors ([#5487](https://github.com/algolia/instantsearch.js/issues/5487)) ([33fe510](https://github.com/algolia/instantsearch.js/commit/33fe510307e4b382a5ba1153a0eaf160420acd11)) ([#5606](https://github.com/algolia/instantsearch.js/issues/5606)) ([bdd9290](https://github.com/algolia/instantsearch.js/commit/bdd92901b59ae4e5d7311eadfbf53ed656bbaf4a)) ([#5512](https://github.com/algolia/instantsearch.js/issues/5512)) ([85dfbc9](https://github.com/algolia/instantsearch.js/commit/85dfbc9ebd722fbe6a7e1bd056950fdbcc16d8d9)) -* **metadata:** register metadata around middleware ([#5492](https://github.com/algolia/instantsearch.js/issues/5492)) ([3e72ec8](https://github.com/algolia/instantsearch.js/commit/3e72ec82894a05a071328a4802d2f764233fe005)) - - - - - -## [6.42.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.1...react-instantsearch-hooks-web@6.42.2) (2023-04-11) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.42.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.0...react-instantsearch-hooks-web@6.42.1) (2023-03-28) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.42.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.41.0...react-instantsearch-hooks-web@6.42.0) (2023-03-21) - - -### Bug Fixes - -* **searchbox:** add aria-hidden to svg icons ([#5547](https://github.com/algolia/instantsearch.js/issues/5547)) ([50344e3](https://github.com/algolia/instantsearch.js/commit/50344e3b14c22c886415c0e7d799aca778dc39ab)), closes [#5546](https://github.com/algolia/instantsearch.js/issues/5546) - - - - - -## [6.41.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.1...react-instantsearch-hooks-web@6.41.0) (2023-03-07) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.1...react-instantsearch-hooks-web@6.40.2) (2023-02-28) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.0...react-instantsearch-hooks-web@6.40.1) (2023-02-21) - - -### Bug Fixes - -* **breadcrumb:** guard against undefined facets ([#5482](https://github.com/algolia/instantsearch.js/issues/5482)) ([3159afe](https://github.com/algolia/instantsearch.js/commit/3159afe57472fe2b669dceb5f1ee638b658f7f52)) - - - - - -## [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.3...react-instantsearch-hooks-web@6.40.0) (2023-02-14) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.39.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.2...react-instantsearch-hooks-web@6.39.3) (2023-02-07) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.1...react-instantsearch-hooks-web@6.39.2) (2023-01-30) - - -### Bug Fixes - -* **infiniteHits:** read cache correctly when search is loading ([#5461](https://github.com/algolia/instantsearch.js/issues/5461)) ([bfabe00](https://github.com/algolia/instantsearch.js/commit/bfabe002a26e15e13b33200c355379f4e3c60f21)) - - - - - -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.0...react-instantsearch-hooks-web@6.39.1) (2023-01-26) - - -### Bug Fixes - -* **dependencies:** update typescript ([#5454](https://github.com/algolia/instantsearch.js/issues/5454)) ([0e6bb48](https://github.com/algolia/instantsearch.js/commit/0e6bb485a31cd3294436ac9902c2c2662dfcdf8b)) -* **HierarchicalMenu:** don't give --parent class if data is empty ([#5458](https://github.com/algolia/instantsearch.js/issues/5458)) ([1d1a209](https://github.com/algolia/instantsearch.js/commit/1d1a209992e86b720939607cd22e37a04e865195)), closes [/github.com/algolia/instantsearch/blob/f84c01b2f66ac279f7e33fafe5f1cd559436edef/packages/instantsearch.js/src/components/RefinementList/RefinementList.tsx#L175-L179](https://github.com//github.com/algolia/instantsearch/blob/f84c01b2f66ac279f7e33fafe5f1cd559436edef/packages/instantsearch.js/src/components/RefinementList/RefinementList.tsx/issues/L175-L179) - - - - - -# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.3...react-instantsearch-hooks-web@6.39.0) (2023-01-25) - - -### Features - -* **react-instantsearch-hooks-web:** Add stats widget and ui component ([#5427](https://github.com/algolia/instantsearch.js/issues/5427)) ([d07cf0d](https://github.com/algolia/instantsearch.js/commit/d07cf0d0310bf4e49d4a4c2142b3783d9bcda79d)) -* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) -* **rendering:** revert search state on error ([#5438](https://github.com/algolia/instantsearch.js/issues/5438)) ([732fcac](https://github.com/algolia/instantsearch.js/commit/732fcac79ea1f51b19f62d5c4bf1fdf22619fa73)) - - - - - -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.2...react-instantsearch-hooks-web@6.38.3) (2023-01-09) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.1...react-instantsearch-hooks-web@6.38.2) (2023-01-03) - -**Note:** Version bump only for package react-instantsearch-hooks-web - - - - - -## [6.38.1](https://github.com/algolia/react-instantsearch/compare/v6.38.0...v6.38.1) (2022-11-08) - - -### Bug Fixes - -* **hooks:** avoid effect in useStableValue ([#3670](https://github.com/algolia/react-instantsearch/issues/3670)) ([d1f53ae](https://github.com/algolia/react-instantsearch/commit/d1f53ae815b75f13c18fd245e0403d57e7ae391c)) - - - -# [6.38.0](https://github.com/algolia/react-instantsearch/compare/v6.37.0...v6.38.0) (2022-10-25) - - -### Features - -* **getServerState:** allow users to inject renderToString ([#3658](https://github.com/algolia/react-instantsearch/issues/3658)) ([9c10449](https://github.com/algolia/react-instantsearch/commit/9c104497b9b32337f288d70a2582c41cafb13cd6)), closes [#3633](https://github.com/algolia/react-instantsearch/issues/3633) [#3618](https://github.com/algolia/react-instantsearch/issues/3618) [vercel/next.js#40067](https://github.com/vercel/next.js/issues/40067) - -* **PoweredBy:** update component logo ([#3661](https://github.com/algolia/react-instantsearch/issues/3661)) ([69c1b2a](https://github.com/algolia/react-instantsearch/commit/69c1b2acef64d972dfa6c6beb8967032119ad2d5)) - - - -# [6.37.0](https://github.com/algolia/react-instantsearch/compare/v6.36.0...v6.37.0) (2022-10-18) - - -### Features - -* **core:** support react 18 strict mode ([#3653](https://github.com/algolia/react-instantsearch/issues/3653)) ([9174806](https://github.com/algolia/react-instantsearch/commit/9174806a7997a45893a24d149027119f4a0709c3)) - - - -# [6.36.0](https://github.com/algolia/react-instantsearch/compare/v6.35.0...v6.36.0) (2022-10-04) - - -### Features - -* **HierarchicalMenu:** add css class for link of selected menu item ([#3646](https://github.com/algolia/react-instantsearch/issues/3646)) ([980ad70](https://github.com/algolia/react-instantsearch/commit/980ad70c75e970c35c11a10a534dbe3996d6c54c)) -* **useInstantSearch:** expose status & error ([#3645](https://github.com/algolia/react-instantsearch/issues/3645)) ([f436d31](https://github.com/algolia/react-instantsearch/commit/f436d31184f3f75b33a1fdaa19c665e77948df28)) - - - -# [6.35.0](https://github.com/algolia/react-instantsearch/compare/v6.34.0...v6.35.0) (2022-09-29) - - -### Features - -* **hooks-web:** introduce Translations API ([#3638](https://github.com/algolia/react-instantsearch/issues/3638)) ([63b506f](https://github.com/algolia/react-instantsearch/commit/63b506f9dbad284f45ac17210e17c4a2a8f099b6)) - -### Fixes -* **hooks-web:** when searchAsYouType=false, pressing the reset button searches (previously only reset the query) ([#3642](https://github.com/algolia/react-instantsearch/issues/3642)) ([f969deb](https://github.com/algolia/react-instantsearch/commit/f969deb05fd4f53aaa251ff88b52db2224ce0786)) - -# [6.34.0](https://github.com/algolia/react-instantsearch/compare/v6.33.0...v6.34.0) (2022-09-27) - - -### Features - -* **SearchBox:** expose formRef ([#3565](https://github.com/algolia/react-instantsearch/issues/3565)) ([1c2f46d](https://github.com/algolia/react-instantsearch/commit/1c2f46da2d1cf705cfd3946c52aef4ca9ec943d7)) - - - -# [6.33.0](https://github.com/algolia/react-instantsearch/compare/v6.32.1...v6.33.0) (2022-09-15) - - -### Bug Fixes - -* **react-native:** mark as compatible with react 18 ([#3614](https://github.com/algolia/react-instantsearch/issues/3614)) ([2a191a8](https://github.com/algolia/react-instantsearch/commit/2a191a84751127de5a3eb34b59b460a1d1bfe594)) -* **rish:** hide reset button when search is stalled in `SearchBox` ([#3617](https://github.com/algolia/react-instantsearch/issues/3617)) ([93ee9d0](https://github.com/algolia/react-instantsearch/commit/93ee9d0212893cef4842c86b7c78f285aa136be8)) - - -### Features - -* **dependencies:** update instantsearch and helper ([#3622](https://github.com/algolia/react-instantsearch/issues/3622)) ([6773ab1](https://github.com/algolia/react-instantsearch/commit/6773ab169cd74dfe1133e255daade4d57e99d9a4)) - - - -## [6.32.1](https://github.com/algolia/react-instantsearch/compare/v6.32.0...v6.32.1) (2022-08-26) - - -### Bug Fixes - -* **useInstantSearch:** prevent `results` from being `null` when first search is stalled ([#3597](https://github.com/algolia/react-instantsearch/issues/3597)) ([6f71d78](https://github.com/algolia/react-instantsearch/commit/6f71d78868fde55a3f9c4460edc337a1e99df4f9)) - - - -# [6.32.0](https://github.com/algolia/react-instantsearch/compare/v6.31.1...v6.32.0) (2022-08-22) - - -### Features - -* **SearchBox:** introduce `autoFocus` prop ([#3599](https://github.com/algolia/react-instantsearch/issues/3599)) ([99121b9](https://github.com/algolia/react-instantsearch/commit/99121b952fd002cb6dae52af41f08beed8f6c3e2)) - - - -## [6.31.1](https://github.com/algolia/react-instantsearch/compare/v6.31.0...v6.31.1) (2022-08-08) - - -### Bug Fixes - -* **hooks:** prevent widget cleanup on `` unmount ([#3590](https://github.com/algolia/react-instantsearch/issues/3590)) ([d94899d](https://github.com/algolia/react-instantsearch/commit/d94899d1264134f0cb1ca2d266a660f1fb2a588c)) - - - -# [6.31.0](https://github.com/algolia/react-instantsearch/compare/v6.30.3...v6.31.0) (2022-08-03) - - -### Features - -* **hooks:** add `searchAsYouType` option to `` ([#3585](https://github.com/algolia/react-instantsearch/issues/3585)) ([c610385](https://github.com/algolia/react-instantsearch/commit/c610385cb9688b23b3e041e31b9edd60392b341d)) - - - -## [6.30.3](https://github.com/algolia/react-instantsearch/compare/v6.30.2...v6.30.3) (2022-08-01) - - -### Bug Fixes - -* **hooks:** replace `labelText` CSS class with `label` in `` to align with InstantSearch's CSS specifications ([#3583](https://github.com/algolia/react-instantsearch/issues/3583)) ([3e030ae](https://github.com/algolia/react-instantsearch/commit/3e030aedb9f285ff449eb82589bc6fea60b160cb)) - - - -## [6.30.2](https://github.com/algolia/react-instantsearch/compare/v6.30.1...v6.30.2) (2022-07-18) - - -### Bug Fixes - -* **hooks:** type of DynamicWidgets props ([#3566](https://github.com/algolia/react-instantsearch/issues/3566)) ([612c98b](https://github.com/algolia/react-instantsearch/commit/612c98b5a77fb9037185c4b5efda8c07663dbd1a)), closes [#3563](https://github.com/algolia/react-instantsearch/issues/3563) -* **hooks:** use single instance in ([#3561](https://github.com/algolia/react-instantsearch/issues/3561)) ([4c358be](https://github.com/algolia/react-instantsearch/commit/4c358bebfc91451b1610f677f89c595d7a427f1f)) - - - -## [6.30.1](https://github.com/algolia/react-instantsearch/compare/v6.30.0...v6.30.1) (2022-07-12) - - -### Bug Fixes - -* **hooks:** provide state and results APIs from "render" event ([#3554](https://github.com/algolia/react-instantsearch/issues/3554)) ([67d4788](https://github.com/algolia/react-instantsearch/commit/67d4788ab09ec2a57b43d53e8093b8c11120b761)) -* **hooks**: update instantsearch.js dependency ([#3557](https://github.com/algolia/react-instantsearch/issues/3557)) - - - -# [6.30.0](https://github.com/algolia/react-instantsearch/compare/v6.29.0...v6.30.0) (2022-07-05) - - -### Features - -* **core:** update instantsearch and helper ([#3539](https://github.com/algolia/react-instantsearch/issues/3539)) ([0ac2c7a](https://github.com/algolia/react-instantsearch/commit/0ac2c7a3f2e2a827721f5b2b7c69c54560f8574f)) - - - -# [6.29.0](https://github.com/algolia/react-instantsearch/compare/v6.28.0...v6.29.0) (2022-06-21) - - -### Bug Fixes - -* **HierarchicalMenu:** show full hierarchical parent values ([#3521](https://github.com/algolia/react-instantsearch/issues/3521)) ([79c3890](https://github.com/algolia/react-instantsearch/commit/79c3890848175a4d70311e5c3929c902bb953c10)) - - -### Features - -* **core:** sort parameters for improved cache rate ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) -* **core:** support client.search for sffv ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) - - - -# [6.28.0](https://github.com/algolia/react-instantsearch/compare/v6.27.0...v6.28.0) (2022-06-15) - - -### Bug Fixes - -* **hooks-server:** import react server via an expression ([#3515](https://github.com/algolia/react-instantsearch/issues/3515)) ([91b96f7](https://github.com/algolia/react-instantsearch/commit/91b96f743b9315ed5ea781681b77fc7f5604ab6e)), closes [#3512](https://github.com/algolia/react-instantsearch/issues/3512) -* **hooks-web:** fix duplicated key in ([#3513](https://github.com/algolia/react-instantsearch/issues/3513)) ([fc94d80](https://github.com/algolia/react-instantsearch/commit/fc94d806daf139f58b234cdc0b450da2efe861ee)) -* **hooks:** mount widgets in SSR to retrieve HTML ([#3518](https://github.com/algolia/react-instantsearch/issues/3518)) ([aa5f9d8](https://github.com/algolia/react-instantsearch/commit/aa5f9d84ddb6e97d05e6ad1baf2c6caa23891281)) -* **types:** allow useInstantSearch to be generic ([#3508](https://github.com/algolia/react-instantsearch/issues/3508)) ([6807232](https://github.com/algolia/react-instantsearch/commit/68072324cf302801502a1b4c3d06703e57b55a97)), closes [algolia/instantsearch.js#5060](https://github.com/algolia/instantsearch.js/issues/5060) -* **types:** support React 18 types ([#3481](https://github.com/algolia/react-instantsearch/issues/3481)) ([74cf8cb](https://github.com/algolia/react-instantsearch/commit/74cf8cb9be8ff3d113b57a50e7083df0d1bc94f2)) - - -### Features - -* **hooks:** introduce `useInstantSearch()` ([#3494](https://github.com/algolia/react-instantsearch/issues/3494)) ([74d522c](https://github.com/algolia/react-instantsearch/commit/74d522c032326658f2a0b8f0001bd593e0085208)) -* **hooks:** support React 18 Strict Mode ([#3514](https://github.com/algolia/react-instantsearch/issues/3514)) ([eeb67c7](https://github.com/algolia/react-instantsearch/commit/eeb67c7b5dc08c696c46d9538f104eeceecef388)) - - - -# [6.27.0](https://github.com/algolia/react-instantsearch/compare/v6.26.0...v6.27.0) (2022-06-07) - - -### Bug Fixes - -* **hooks-web:** don't pass widget props to ui components ([#3501](https://github.com/algolia/react-instantsearch/issues/3501)) ([5bd53c1](https://github.com/algolia/react-instantsearch/commit/5bd53c128ddeeea87f75ae89eb8f2324d476c70e)), closes [#3499](https://github.com/algolia/react-instantsearch/issues/3499) -* **SearchBox-hooks:** correctly pass widget props ([#3499](https://github.com/algolia/react-instantsearch/issues/3499)) ([2cdf906](https://github.com/algolia/react-instantsearch/commit/2cdf90602b7c2c5895124ef64c389ce574154386)), closes [#3498](https://github.com/algolia/react-instantsearch/issues/3498) - - -### Features - -* **hooks:** migrate to `useSyncExternalStore()` ([#3489](https://github.com/algolia/react-instantsearch/issues/3489)) ([81bbdf2](https://github.com/algolia/react-instantsearch/commit/81bbdf28f2d28d8b0081cfd7d9e84c3e33038dd2)) -* **hooks:** upgrade to InstantSearch.js 4.41.0 ([#3502](https://github.com/algolia/react-instantsearch/issues/3502)) ([0b76792](https://github.com/algolia/react-instantsearch/commit/0b76792ea0c4e2ac9fe742810d70ba1aee2a3e79)) - - - -# [6.26.0](https://github.com/algolia/react-instantsearch/compare/v6.25.0...v6.26.0) (2022-05-19) - - -### Features - -* **hooks-web:** expose `sendEvent` to `hitComponent` ([#3476](https://github.com/algolia/react-instantsearch/issues/3476)) ([5cc18d1](https://github.com/algolia/react-instantsearch/commit/5cc18d19d9f22305f33d92e43fd0aca2a5cb949a)) -* **react-instantsearch-core:** allow widgets to set their `$$widgetType` ([#3472](https://github.com/algolia/react-instantsearch/issues/3472)) ([1c436e1](https://github.com/algolia/react-instantsearch/commit/1c436e1429ab4230bbfea7c6d2474d141f5c5c64)) - - - -# [6.25.0](https://github.com/algolia/react-instantsearch/compare/v6.24.3...v6.25.0) (2022-05-17) - - -### Bug Fixes - -* **hooks-highlight:** make sure highlight and snippet don't show html-escaped content ([#3471](https://github.com/algolia/react-instantsearch/issues/3471)) ([c18ddd2](https://github.com/algolia/react-instantsearch/commit/c18ddd25faca37d6bfa3d1c28f6fc22ec5fcf6d8)) -* **hooks-server:** remove faulty UMD build ([#3465](https://github.com/algolia/react-instantsearch/issues/3465)) ([c1ddfe4](https://github.com/algolia/react-instantsearch/commit/c1ddfe408b411551ac8524877a9d65ded8133c42)) - - -### Features - -* **dom-maps:** expose GeoSearchContext ([#3468](https://github.com/algolia/react-instantsearch/issues/3468)) ([a61ff96](https://github.com/algolia/react-instantsearch/commit/a61ff96222bfd4f6301cf93bf95e2fa18b263d3c)), closes [#3448](https://github.com/algolia/react-instantsearch/issues/3448) -* **hooks-server:** support import from React 18 ([#3464](https://github.com/algolia/react-instantsearch/issues/3464)) ([0a13867](https://github.com/algolia/react-instantsearch/commit/0a13867f7dd5a8a18e0957b2072bbde3b02d6490)), closes [#3453](https://github.com/algolia/react-instantsearch/issues/3453) -* **hooks:** make InstantSearch type generic ([#3466](https://github.com/algolia/react-instantsearch/issues/3466)) ([b0905b7](https://github.com/algolia/react-instantsearch/commit/b0905b73bed558c62eedb7ae701be20c2ebe25c9)) - - - -## [6.24.3](https://github.com/algolia/react-instantsearch/compare/v6.24.2...v6.24.3) (2022-05-10) - - -### Bug Fixes - -* **numericmenu:** include range values in comparison with minmax bounds ([#3461](https://github.com/algolia/react-instantsearch/issues/3461)) ([e4c2682](https://github.com/algolia/react-instantsearch/commit/e4c268261dc42a6aa43d985934b53c82f8b71089)) - - - -## [6.24.2](https://github.com/algolia/react-instantsearch/compare/v6.24.1...v6.24.2) (2022-05-05) - - -### Bug Fixes - -* **hooks:** prevent infinite loops from render state ([#3455](https://github.com/algolia/react-instantsearch/issues/3455)) ([1799fc9](https://github.com/algolia/react-instantsearch/commit/1799fc9f78a4a5aafb54df339c3e211ff9187748)) - - - -## [6.24.1](https://github.com/algolia/react-instantsearch/compare/v6.24.0...v6.24.1) (2022-05-03) - - -### Bug Fixes - -* **types:** export correct types for react-instantsearch-hooks-web ([#3454](https://github.com/algolia/react-instantsearch/issues/3454)) ([a863430](https://github.com/algolia/react-instantsearch/commit/a8634306621f7a05a2b3056a6db25ccf8d9eabf0)) - - - -# [6.24.0](https://github.com/algolia/react-instantsearch/compare/v6.23.4...v6.24.0) (2022-04-28) - - -### Features - -* **hooks:** expose DOM components ([#3450](https://github.com/algolia/react-instantsearch/issues/3450)) ([5732e3d](https://github.com/algolia/react-instantsearch/commit/5732e3de732275911f94b26ba9e2c4165bdf77e7)) -* **hooks:** remove experimental warning ([#3446](https://github.com/algolia/react-instantsearch/issues/3446)) ([84c99fe](https://github.com/algolia/react-instantsearch/commit/84c99fe91d6906a877bec620b44c61d762f0ea57)) - - - -## [6.23.4](https://github.com/algolia/react-instantsearch/compare/v6.23.3...v6.23.4) (2022-04-21) - - -### Bug Fixes - -* **hooks:** forbid importing from instantsearch.js root path ([#3437](https://github.com/algolia/react-instantsearch/issues/3437)) ([82ef9ea](https://github.com/algolia/react-instantsearch/commit/82ef9eaaec42bc54f15796b5b031a8656330a45c)) -* **packages:** correctly mark peer dependency ([#3439](https://github.com/algolia/react-instantsearch/issues/3439)) ([51e8818](https://github.com/algolia/react-instantsearch/commit/51e8818fce224819230c8bf6dea2a08d71d9be29)), closes [#3428](https://github.com/algolia/react-instantsearch/issues/3428) - - - -## [6.23.3](https://github.com/algolia/react-instantsearch/compare/v6.23.2...v6.23.3) (2022-04-05) - - -### Bug Fixes - -* **facets:** show raw value in currentRefinements ([#3420](https://github.com/algolia/react-instantsearch/issues/3420)) ([1199ce6](https://github.com/algolia/react-instantsearch/commit/1199ce6bd4152e4b54bd2ee0e1f0c9d81021c7d5)), closes [#3412](https://github.com/algolia/react-instantsearch/issues/3412) -* **multi-index:** correctly set `searching` prop in multi-index result states ([#3419](https://github.com/algolia/react-instantsearch/issues/3419)) ([7f8e97e](https://github.com/algolia/react-instantsearch/commit/7f8e97e31b3dd5e49d3febef673f41f7dfa6d45d)) - - - -## [6.23.2](https://github.com/algolia/react-instantsearch/compare/v6.23.1...v6.23.2) (2022-04-04) - - -### Bug Fixes - -* **refinements:** use escaped value for refining ([#3412](https://github.com/algolia/react-instantsearch/issues/3412)) ([f2f5f6c](https://github.com/algolia/react-instantsearch/commit/f2f5f6cbfaed48a5c494daeb8789e8deebc64293)) -* support React 18 as peer dependency ([#3411](https://github.com/algolia/react-instantsearch/issues/3411)) ([38eb5a6](https://github.com/algolia/react-instantsearch/commit/38eb5a6a8fe92cb763a25f452bea78b189a6a82a)) - - -## [6.23.1](https://algolia/compare/v6.23.0...v6.23.1) (2022-03-30) - - -### Bug Fixes - -* **hooks:** compute initial search parameters from widget ([#3399](https://algolia/issues/3399)) ([b4bd933](https://algolia/commits/b4bd93358598bdc77a1aa858252e6eee23441345)) - - - -# [6.23.0](https://algolia/compare/v6.22.0...v6.23.0) (2022-03-23) - - -### Bug Fixes - -* **ssr:** perform initial multi-index search using a single request ([#3385](https://algolia/issues/3385)) ([b96809e](https://algolia/commits/b96809e5748d298350890647956cb7adbbb55650)) - - -### Features - -* **hooks:** allow additional widget properties to be passed from hooks ([#3359](https://algolia/issues/3359)) ([a047be4](https://algolia/commits/a047be45c7fce7ee28f7d6f61d2fbfa79e3ed2d0)) -* **hooks:** allow useHits and useInfiniteHit to be generic ([#3364](https://algolia/issues/3364)) ([8e66ad3](https://algolia/commits/8e66ad3ad587197c4811c60a5cab475137ca5afb)) -* **hooks:** mark initial results as "artificial" ([#3384](https://algolia/issues/3384)) ([937efdc](https://algolia/commits/937efdc71bae1d99270f8ecb5c5c9c501b3d7769)) - - - -# [6.22.0](https://github.com/algolia/react-instantsearch/compare/v6.21.1...v6.22.0) (2022-02-01) - - -### Bug Fixes - -* **hooks:** enable pause on exceptions on warning ([#3283](https://github.com/algolia/react-instantsearch/issues/3283)) ([ce3a6c3](https://github.com/algolia/react-instantsearch/commit/ce3a6c3f2700a05ae54a91278fd23fa64a97d733)) - - -### Features - -* **hooks:** introduce `useBreadcrumb()` ([#3245](https://github.com/algolia/react-instantsearch/issues/3245)) ([5bfbaaf](https://github.com/algolia/react-instantsearch/commit/5bfbaaf746e7632968ac9b30b73357bcb0b37e91)) - - - -## [6.21.1](https://github.com/algolia/react-instantsearch/compare/v6.21.0...v6.21.1) (2022-01-25) - - -### Bug Fixes - -* **hooks:** apply initial search parameters in useConnector ([#3276](https://github.com/algolia/react-instantsearch/issues/3276)) ([f85d679](https://github.com/algolia/react-instantsearch/commit/f85d6794c31eac61521fd8fc16b75673f02ed75b)) - - - -# [6.21.0](https://github.com/algolia/react-instantsearch/compare/v6.20.0...v6.21.0) (2022-01-24) - - -### Features - -* **hooks-server:** load data twice in the case of dynamic widget usage ([#3259](https://github.com/algolia/react-instantsearch/issues/3259)) ([9b4903b](https://github.com/algolia/react-instantsearch/commit/9b4903b2ea73d9d7e33729b87d9d55990e64312c)) -* **server:** load data twice in the case of dynamic widget usage ([#3268](https://github.com/algolia/react-instantsearch/issues/3268)) ([91cd085](https://github.com/algolia/react-instantsearch/commit/91cd085f9a323ed6b872f3a098f561007a72d0d2)), closes [/github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js#L14-L16](https://github.com//github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js/issues/L14-L16) - - - -# [6.20.0](https://github.com/algolia/react-instantsearch/compare/v6.19.0...v6.20.0) (2022-01-18) - - -### Bug Fixes - -* **hooks:** allow importing via require ([#3257](https://github.com/algolia/react-instantsearch/issues/3257)) ([6aa80b3](https://github.com/algolia/react-instantsearch/commit/6aa80b3647567199c3df1b90a07d708b223ce1fd)) - - -### Features - -* **hooks:** implement `useClearRefinements()` ([#3256](https://github.com/algolia/react-instantsearch/issues/3256)) ([930b83d](https://github.com/algolia/react-instantsearch/commit/930b83df4c4bbccbc3118f6ea1001f6a30a3d464)), closes [#3252](https://github.com/algolia/react-instantsearch/issues/3252) -* **hooks:** introduce `` ([#3261](https://github.com/algolia/react-instantsearch/issues/3261)) ([3527b94](https://github.com/algolia/react-instantsearch/commit/3527b9422de48a4a6b4bd752bd643e01cd5011d8)) -* **hooks:** introduce `usePoweredBy()` ([#3251](https://github.com/algolia/react-instantsearch/issues/3251)) ([a97230b](https://github.com/algolia/react-instantsearch/commit/a97230b89e3ba1df9bf2d21a6a9f9a70b45f41b8)) -* **hooks:** introduce `useToggleRefinement()` ([#3248](https://github.com/algolia/react-instantsearch/issues/3248)) ([a561c09](https://github.com/algolia/react-instantsearch/commit/a561c090a268e1c6ca1fa2d5bf72263cc47aa273)) - - - -# [6.19.0](https://github.com/algolia/react-instantsearch/compare/v6.18.0...v6.19.0) (2022-01-05) - - -### Features - -* **hooks:** bundle as es-module ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) -* **dependencies:** update to latest algoliasearch-helper ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) - - - -# [6.18.0](https://github.com/algolia/react-instantsearch/compare/v6.17.0...v6.18.0) (2021-12-16) - - -### Features - -* **dynamicWidgets:** send facets * and maxValuesPerFacet by default ([#3242](https://github.com/algolia/react-instantsearch/issues/3242)) ([c071776](https://github.com/algolia/react-instantsearch/commit/c07177670ac30dced55250774654e8b2a77b6739)) -* **hooks:** introduce `useNumericMenu()` ([#3237](https://github.com/algolia/react-instantsearch/issues/3237)) ([e3056c9](https://github.com/algolia/react-instantsearch/commit/e3056c9e2c64b5afafb7a736599a5cbf6137575b)) -* **hooks:** introduce `useInfiniteHits()` ([#3224](https://github.com/algolia/react-instantsearch/issues/3224)) ([177ec56](https://github.com/algolia/react-instantsearch/commit/177ec56af274670c2bf8599ba104b5544979bbe8)) - - - -# [6.17.0](https://github.com/algolia/react-instantsearch/compare/v6.16.0...v6.17.0) (2021-12-08) - - -### Bug Fixes - -* **hooks:** throw invariant violations in production ([#3217](https://github.com/algolia/react-instantsearch/issues/3217)) ([6d3f99c](https://github.com/algolia/react-instantsearch/commit/6d3f99ca91f470ee742ddc55e95f57b1f1801d7b)) - - -### Features - -* **hooks:** introduce `useMenu()` ([#3197](https://github.com/algolia/react-instantsearch/issues/3197)) ([15d1cc9](https://github.com/algolia/react-instantsearch/commit/15d1cc993437b111cd5a32f43ee1d2065c639ed4)) -* **hooks:** introduce `useRange()` ([#3198](https://github.com/algolia/react-instantsearch/issues/3198)) ([df1f1c8](https://github.com/algolia/react-instantsearch/commit/df1f1c8109dc684e74d3aee1bf0359f2a0e1b9f4)) -* **hooks:** introduce `` ([#3216](https://github.com/algolia/react-instantsearch/issues/3216)) ([d99aea6](https://github.com/algolia/react-instantsearch/commit/d99aea6cfe9dea86ae6b98ee3762373f4b3843f1)) -* **hooks:** introduce `useDynamicWidgets()` ([#3210](https://github.com/algolia/react-instantsearch/issues/3210)) ([29c2ea2](https://github.com/algolia/react-instantsearch/commit/29c2ea22b91a39d9eb40a044ae9aab85f2612db8)) -* **hooks:** introduce `useQueryRules()` ([#3212](https://github.com/algolia/react-instantsearch/issues/3212)) ([3ef1e1e](https://github.com/algolia/react-instantsearch/commit/3ef1e1e4116b3e58b2c2134d0c60fbb9f40c1501)) -* **hooks:** introduce SSR support ([#3221](https://github.com/algolia/react-instantsearch/issues/3221)) ([0a6b3ec](https://github.com/algolia/react-instantsearch/commit/0a6b3ec61942ad3849c6f078e21b3328679bffff)) -* **hooks:** introduce `useCurrentRefinements()` ([#3222](https://github.com/algolia/react-instantsearch/issues/3222)) ([7ebd8c3](https://github.com/algolia/react-instantsearch/commit/7ebd8c3da8c17b0bd7e0f8deab633b98fa052e7f)) - - - -# [6.16.0](https://github.com/algolia/react-instantsearch/compare/v6.15.0...v6.16.0) (2021-11-22) - - -### Bug Fixes - -* **PoweredBy:** support environments with `window` but no `location` ([#3186](https://github.com/algolia/react-instantsearch/issues/3186)) ([22ff23b](https://github.com/algolia/react-instantsearch/commit/22ff23b67554683567393114c2f53cacec44f4a6)) - - -### Features - -* **DynamicWidgets:** release as stable ([#3090](https://github.com/algolia/react-instantsearch/issues/3090)) ([a4a1d9e](https://github.com/algolia/react-instantsearch/commit/a4a1d9e032b31c611d5d73fdda3a03ad705f5c68)) -* **hooks:** introduce `usePagination()` ([#3182](https://github.com/algolia/react-instantsearch/issues/3182)) ([d8b1b86](https://github.com/algolia/react-instantsearch/commit/d8b1b867bb598e801f1350e81b4a4220a8e528d7)) -* **hooks:** introduce `useSortBy()` ([#3190](https://github.com/algolia/react-instantsearch/issues/3190)) ([5cce33b](https://github.com/algolia/react-instantsearch/commit/5cce33b48032548fed76b592ee0201e3c42fc3c4)) -* **hooks:** introduce `useHierarchicalMenu()` ([#3199](https://github.com/algolia/react-instantsearch/issues/3199)) ([b347061](https://github.com/algolia/react-instantsearch/commit/b3470611b962ef55c55576c65a6307abc54e5efd)) - - - -# [6.15.0](https://github.com/algolia/react-instantsearch/compare/v6.14.0...v6.15.0) (2021-10-27) - - -### Bug Fixes - -* **metadata:** stricter detection of user agent ([#3184](https://github.com/algolia/react-instantsearch/issues/3184)) ([994c8ae](https://github.com/algolia/react-instantsearch/commit/994c8ae055fc23a1a067d111d2f4727b1c7bf8ca)) - - -### Features - -* **hooks:** introduce `useConfigure()` ([#3181](https://github.com/algolia/react-instantsearch/issues/3181)) ([aa2eb9b](https://github.com/algolia/react-instantsearch/commit/aa2eb9baec6335f8a3523ee8b9b761a217cfc734)) - - - -# [6.14.0](https://github.com/algolia/react-instantsearch/compare/v6.13.0...v6.14.0) (2021-10-26) - - -### Features - -* **dependencies:** update algoliasearch-helper ([#3176](https://github.com/algolia/react-instantsearch/issues/3176)) ([a8708a3](https://github.com/algolia/react-instantsearch/commit/a8708a33f31632000bc827b076539b1cca7adf6f)) -* **metadata:** expose widget information ([#3145](https://github.com/algolia/react-instantsearch/issues/3145)) ([46cddf8](https://github.com/algolia/react-instantsearch/commit/46cddf8fcc0291beaa34b04da7aaaa7f2566e52e)) - - - -# [6.13.0](https://github.com/algolia/react-instantsearch/compare/v6.12.1...v6.13.0) (2021-10-19) - -This is the initial release of the experimental **React InstantSearch Hooks** package. Check out the [**Getting Started**](https://github.com/algolia/react-instantsearch/blob/e8d72cb1c7c45300ef7c273f1f163beb6dc57622/packages/react-instantsearch-hooks/README.md#getting-started) guide. - -### Bug Fixes - -- **core:** accept objects for `hitComponent` ([#3087](https://github.com/algolia/react-instantsearch/issues/3087)) ([4ae23d4](https://github.com/algolia/react-instantsearch/commit/4ae23d432a01ccbefff1fcdc865120aeca4d3efc)) - -### Features - -- **hooks:** add InstantSearch and Index components ([#3133](https://github.com/algolia/react-instantsearch/issues/3133)) ([8e3370d](https://github.com/algolia/react-instantsearch/commit/8e3370ddb7d5e42b8b9a5ff6a1e4255490de7dbe)) -- **hooks:** bootstrap Core package ([#3132](https://github.com/algolia/react-instantsearch/issues/3132)) ([d459e62](https://github.com/algolia/react-instantsearch/commit/d459e62f5cae4c98427ab302531873f5ee23d149)) -- **hooks:** display experimental warning ([#3149](https://github.com/algolia/react-instantsearch/issues/3149)) ([623577c](https://github.com/algolia/react-instantsearch/commit/623577c50cd0c04cd87f719edafdcfa04b5527b6)) -- **hooks:** export types ([#3159](https://github.com/algolia/react-instantsearch/issues/3159)) ([182348b](https://github.com/algolia/react-instantsearch/commit/182348b4a901823a7a41aee5d2b3bdc025cce48f)) -- **hooks:** expose `displayName` on Contexts ([#3168](https://github.com/algolia/react-instantsearch/issues/3168)) ([dafd3c6](https://github.com/algolia/react-instantsearch/commit/dafd3c66d05fbec09ebf907209ac25f55804e6f5)) -- **hooks:** friendly error when using Hooks with Core ([#3150](https://github.com/algolia/react-instantsearch/issues/3150)) ([d547ccf](https://github.com/algolia/react-instantsearch/commit/d547ccf7951299e2f6b1771e02fce052696ff65a)) -- **hooks:** introduce `useConnector()` ([#3137](https://github.com/algolia/react-instantsearch/issues/3137)) ([53e8afd](https://github.com/algolia/react-instantsearch/commit/53e8afd093b9950351467a16b82d528207ac34d2)) -- **hooks:** introduce `useHits()` ([#3147](https://github.com/algolia/react-instantsearch/issues/3147)) ([cc25cff](https://github.com/algolia/react-instantsearch/commit/cc25cff06e5ec216cba40fb8261372bc327001b6)) -- **hooks:** introduce `useRefinementList()` ([#3152](https://github.com/algolia/react-instantsearch/issues/3152)) ([0385cd9](https://github.com/algolia/react-instantsearch/commit/0385cd971635a8423ad687fab451d0778358389e)) -- **hooks:** introduce `useSearchBox()` ([#3146](https://github.com/algolia/react-instantsearch/issues/3146)) ([0d2c7f9](https://github.com/algolia/react-instantsearch/commit/0d2c7f9bd25b88cf725a1babd3b228ac804644c7)) -- **hooks:** trigger single network request on load ([#3167](https://github.com/algolia/react-instantsearch/issues/3167)) ([ff1ea49](https://github.com/algolia/react-instantsearch/commit/ff1ea49079a7800fd61ba99ceeb74b9f513eb99d)) -- **hooks:** type `useConnector()` return as render state ([#3169](https://github.com/algolia/react-instantsearch/issues/3169)) ([a801468](https://github.com/algolia/react-instantsearch/commit/a80146860164a092d2c90ee0aa4fcef88d5b675f)) -- **hooks:** update GitHub bug reports link ([#3157](https://github.com/algolia/react-instantsearch/issues/3157)) ([568b5c8](https://github.com/algolia/react-instantsearch/commit/568b5c83849a3927417907706656c3835163f216)) - - - -## [6.12.1](https://github.com/algolia/react-instantsearch/compare/v6.12.0...v6.12.1) (2021-08-02) - - -### Bug Fixes - -* **server side rendering:** return a value from mock currentRefinement/metadata ([#3078](https://github.com/algolia/react-instantsearch/issues/3078)) ([09f802b](https://github.com/algolia/react-instantsearch/commit/09f802b)) - - - -# [6.12.0](https://github.com/algolia/react-instantsearch/compare/v6.11.2...v6.12.0) (2021-07-06) - - -### Bug Fixes - -* **HitsPerPage:** Adds id prop to HitsPerPage, Select components ([#3072](https://github.com/algolia/react-instantsearch/issues/3072)) ([bc75d75](https://github.com/algolia/react-instantsearch/commit/bc75d75)) -* **MenuSelect:** Adds id prop to MenuSelect ([#3073](https://github.com/algolia/react-instantsearch/issues/3073)) ([fddaaef](https://github.com/algolia/react-instantsearch/commit/fddaaef)) -* **SearchBox:** Adds inputId prop to SearchBox ([#3074](https://github.com/algolia/react-instantsearch/issues/3074)) ([a05f6a4](https://github.com/algolia/react-instantsearch/commit/a05f6a4)) -* **SortBy:** Adds `id` prop to `SortBy`, `Select` components ([#3068](https://github.com/algolia/react-instantsearch/issues/3068)) ([1f2797f](https://github.com/algolia/react-instantsearch/commit/1f2797f)) - - -### Features - -* **DynamicWidgets:** add implementation ([#3056](https://github.com/algolia/react-instantsearch/issues/3056)) ([691ef87](https://github.com/algolia/react-instantsearch/commit/691ef87)) -* **facets:** add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu ([#3067](https://github.com/algolia/react-instantsearch/issues/3067)) ([731d9ba](https://github.com/algolia/react-instantsearch/commit/731d9ba)) - - - -## [6.11.2](https://github.com/algolia/react-instantsearch/compare/v6.11.1...v6.11.2) (2021-06-28) - - -### Bug Fixes - -* **maps:** leave zoom in place if the bounds did not change ([#3050](https://github.com/algolia/react-instantsearch/issues/3050)) ([c430598](https://github.com/algolia/react-instantsearch/commit/c430598)) - - - -## [6.11.1](https://github.com/algolia/react-instantsearch/compare/v6.11.0...v6.11.1) (2021-06-09) - - -### Bug Fixes - -* **RefinementList:** prevent searchable component to refine on empty list ([#3059](https://github.com/algolia/react-instantsearch/issues/3059)) ([04f3644](https://github.com/algolia/react-instantsearch/commit/04f3644)) - - - -# [6.11.0](https://github.com/algolia/react-instantsearch/compare/v6.10.3...v6.11.0) (2021-05-04) - - -### Features - -* **connectNumericMenu:** add support for floating point values ([#3047](https://github.com/algolia/react-instantsearch/issues/3047)) ([091bf57](https://github.com/algolia/react-instantsearch/commit/091bf57)) - - - -## [6.10.3](https://github.com/algolia/react-instantsearch/compare/v6.10.2...v6.10.3) (2021-03-03) - - -### Bug Fixes - -* **RelevantSort:** Rename `SmartSort` widget to `RelevantSort` ([#3026](https://github.com/algolia/react-instantsearch/issues/3026)) ([47d11bf](https://github.com/algolia/react-instantsearch/commit/47d11bf)) - - - -## [6.10.2](https://github.com/algolia/react-instantsearch/compare/v6.10.1...v6.10.2) (2021-03-03) - - -### Bug Fixes - -* **infiniteHits:** fix stale hits issue ([#3021](https://github.com/algolia/react-instantsearch/issues/3021)) ([a9a29c7](https://github.com/algolia/react-instantsearch/commit/a9a29c7)) - - - -## [6.10.1](https://github.com/algolia/react-instantsearch/compare/v6.10.0...v6.10.1) (2021-03-02) - - -### Bug Fixes - -* **SmartSort:** make `textComponent` and `buttonTextComponent` optional ([#3014](https://github.com/algolia/react-instantsearch/issues/3014)) ([682ee6d](https://github.com/algolia/react-instantsearch/commit/682ee6d)) - - - -# [6.10.0](https://github.com/algolia/react-instantsearch/compare/v6.9.0...v6.10.0) (2021-02-23) - - -### Bug Fixes - -* **infiniteHits:** do not cache the cached hits ([#3011](https://github.com/algolia/react-instantsearch/issues/3011)) ([b56f5f7](https://github.com/algolia/react-instantsearch/commit/b56f5f7)) - - -### Features - -* **smartSort:** add widget ([#3009](https://github.com/algolia/react-instantsearch/issues/3009)) ([4cc8412](https://github.com/algolia/react-instantsearch/commit/4cc8412)), closes [#3010](https://github.com/algolia/react-instantsearch/issues/3010) - - - -# [6.9.0](https://github.com/algolia/react-instantsearch/compare/v6.8.3...v6.9.0) (2021-02-03) - - -### Features - -* **answers:** add `EXPERIMENTAL_Answers` widget ([#2996](https://github.com/algolia/react-instantsearch/issues/2996)) ([55e4191](https://github.com/algolia/react-instantsearch/commit/55e4191)), closes [#3005](https://github.com/algolia/react-instantsearch/issues/3005) - - - -## [6.8.3](https://github.com/algolia/react-instantsearch/compare/v6.8.2...v6.8.3) (2021-01-22) - - -### Bug Fixes - -* upgrade prop-types dependency to 15.6+ ([#3003](https://github.com/algolia/react-instantsearch/issues/3003)) ([fc03496](https://github.com/algolia/react-instantsearch/commit/fc03496)) - - - -## [6.8.2](https://github.com/algolia/react-instantsearch/compare/v6.8.1...v6.8.2) (2020-10-21) - - -### Bug Fixes - -* **ssr:** provide metadata default value ([0a2f34c](https://github.com/algolia/react-instantsearch/commit/0a2f34c)) - - - -## [6.8.1](https://github.com/algolia/react-instantsearch/compare/v6.8.0...v6.8.1) (2020-10-14) - - -### Bug Fixes - -* **ssr:** hydrate metadata with a value ([9249c19](https://github.com/algolia/react-instantsearch/commit/9249c19)) - - - -# [6.8.0](https://github.com/algolia/react-instantsearch/compare/v6.7.0...v6.8.0) (2020-10-14) - - -### Bug Fixes - -* **ssr:** make sure metadata is available on initial render ([#2973](https://github.com/algolia/react-instantsearch/issues/2973)) ([be43b65](https://github.com/algolia/react-instantsearch/commit/be43b65)), closes [#2972](https://github.com/algolia/react-instantsearch/issues/2972) -* add missing dependencies ([#2975](https://github.com/algolia/react-instantsearch/issues/2975)) ([22ecb3c](https://github.com/algolia/react-instantsearch/commit/22ecb3c)) -* **ConfigureRelatedItems:** support nested attributes ([#2967](https://github.com/algolia/react-instantsearch/issues/2967)) ([86dfe86](https://github.com/algolia/react-instantsearch/commit/86dfe86)) -* **ssr:** allow "params" to be optional in custom clients ([#2961](https://github.com/algolia/react-instantsearch/issues/2961)) ([c3e3d2e](https://github.com/algolia/react-instantsearch/commit/c3e3d2e)), closes [#2958](https://github.com/algolia/react-instantsearch/issues/2958) - - - -# [6.7.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.7.0) (2020-07-20) - - -### Bug Fixes - -* **core:** appending successful index search results by returning new object reference ([#2953](https://github.com/algolia/react-instantsearch/issues/2953)) ([0a711a7](https://github.com/algolia/react-instantsearch/commit/0a711a7)) -* **ssr:** remove second instance of "query" in the response "params" for SSR ([#2945](https://github.com/algolia/react-instantsearch/issues/2945)) ([bf837c5](https://github.com/algolia/react-instantsearch/commit/bf837c5)), closes [#2941](https://github.com/algolia/react-instantsearch/issues/2941) - - -### Features - -* **infinite-hits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.6.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.6.0) (2020-06-15) - - -### Features - -* **infiniteHits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.5.0](https://github.com/algolia/react-instantsearch/compare/v6.4.0...v6.5.0) (2020-05-18) - - -### Bug Fixes - -* **connectQueryRules:** fix crash when using connectQueryRules with multiple indexes ([#2903](https://github.com/algolia/react-instantsearch/issues/2903)) ([c66d612](https://github.com/algolia/react-instantsearch/commit/c66d612)) -* **core:** fix maximum call stack size exceeded ([#2926](https://github.com/algolia/react-instantsearch/issues/2926)) ([7e883df](https://github.com/algolia/react-instantsearch/commit/7e883df)) - - -### Features - -* **SearchBox:** provide input element ref ([#2913](https://github.com/algolia/react-instantsearch/issues/2913)) ([b41bff2](https://github.com/algolia/react-instantsearch/commit/b41bff2)) - - - -# [6.4.0](https://github.com/algolia/react-instantsearch/compare/v6.3.0...v6.4.0) (2020-03-18) - - -### Bug Fixes - -* **deps:** fix "too much recursion" error with circular deps ([#2899](https://github.com/algolia/react-instantsearch/issues/2899)) ([c5f27a1](https://github.com/algolia/react-instantsearch/commit/c5f27a1)) - - - -# [6.3.0](https://github.com/algolia/react-instantsearch/compare/v6.2.0...v6.3.0) (2020-01-30) - - -### Features - -* **algoliasearch:** add support for algoliasearch v4 ([#2890](https://github.com/algolia/react-instantsearch/issues/2890)) ([c6c7382](https://github.com/algolia/react-instantsearch/commit/c6c7382)) - - - -# [6.2.0](https://github.com/algolia/react-instantsearch/compare/v6.1.0...v6.2.0) (2020-01-20) - - -### Bug Fixes - -* **deps:** update dependency algoliasearch to v3.35.1 ([#2802](https://github.com/algolia/react-instantsearch/issues/2802)) ([cfb91f0](https://github.com/algolia/react-instantsearch/commit/cfb91f0)) -* **widgets:** rename `ExperimentalConfigureRelatedItems` compon… ([#2891](https://github.com/algolia/react-instantsearch/issues/2891)) ([b910df2](https://github.com/algolia/react-instantsearch/commit/b910df2)) - - -### Features - -* **insights:** add getInsightsAnonymousUserToken helper ([#2887](https://github.com/algolia/react-instantsearch/issues/2887)) ([b5fe4f7](https://github.com/algolia/react-instantsearch/commit/b5fe4f7)) -* **widgets:** introduce `ConfigureRelatedItems` as experimental ([#2880](https://github.com/algolia/react-instantsearch/issues/2880)) ([923cd43](https://github.com/algolia/react-instantsearch/commit/923cd43)) - - - -# [6.1.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0...v6.1.0) (2019-12-17) - - -### Bug Fixes - -* **connectNumericMenu:** support numeric refinement 0 ([#2882](https://github.com/algolia/react-instantsearch/issues/2882)) ([30bd9fd](https://github.com/algolia/react-instantsearch/commit/30bd9fd)) -* **deps:** update dependency next to v9.1.1 ([9d49d33](https://github.com/algolia/react-instantsearch/commit/9d49d33)) -* **helper:** rely on stable version of algoliasearch-helper ([#2871](https://github.com/algolia/react-instantsearch/issues/2871)) ([e3531a1](https://github.com/algolia/react-instantsearch/commit/e3531a1)) - - -### Features - -* **insights:** show an error when 'clickAnalytics: true' is missing. ([#2877](https://github.com/algolia/react-instantsearch/issues/2877)) ([621656a](https://github.com/algolia/react-instantsearch/commit/621656a)) -* **voice:** add additionalQueryParameters ([#2366](https://github.com/algolia/react-instantsearch/issues/2366)) ([3a45b2c](https://github.com/algolia/react-instantsearch/commit/3a45b2c)) - - - -# [6.0.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.2...v6.0.0) (2019-10-28) - - - -# [6.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2019-10-25) - - -### Bug Fixes - -* serialize cache value on hydrate ([#2862](https://github.com/algolia/react-instantsearch/issues/2862)) ([3319665](https://github.com/algolia/react-instantsearch/commit/3319665)), closes [#2828](https://github.com/algolia/react-instantsearch/issues/2828) - - - -# [6.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.1) (2019-10-18) - - -### Bug Fixes - -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **deps:** update dependency antd to v3.19.3 ([#2530](https://github.com/algolia/react-instantsearch/issues/2530)) ([73636c5](https://github.com/algolia/react-instantsearch/commit/73636c5)) -* **deps:** update dependency antd to v3.19.4 ([#2559](https://github.com/algolia/react-instantsearch/issues/2559)) ([c3e8267](https://github.com/algolia/react-instantsearch/commit/c3e8267)) -* **deps:** update dependency antd to v3.19.5 ([#2560](https://github.com/algolia/react-instantsearch/issues/2560)) ([72efd31](https://github.com/algolia/react-instantsearch/commit/72efd31)) -* **deps:** update dependency antd to v3.19.6 ([#2564](https://github.com/algolia/react-instantsearch/issues/2564)) ([654f986](https://github.com/algolia/react-instantsearch/commit/654f986)) -* **deps:** update dependency antd to v3.19.7 ([#2573](https://github.com/algolia/react-instantsearch/issues/2573)) ([7e963ad](https://github.com/algolia/react-instantsearch/commit/7e963ad)) -* **deps:** update dependency antd to v3.19.8 ([#2584](https://github.com/algolia/react-instantsearch/issues/2584)) ([34dd9b2](https://github.com/algolia/react-instantsearch/commit/34dd9b2)) -* **deps:** update dependency antd to v3.20.0 ([#2611](https://github.com/algolia/react-instantsearch/issues/2611)) ([b976c67](https://github.com/algolia/react-instantsearch/commit/b976c67)) -* **deps:** update dependency antd to v3.20.1 ([#2635](https://github.com/algolia/react-instantsearch/issues/2635)) ([792ad9c](https://github.com/algolia/react-instantsearch/commit/792ad9c)) -* **deps:** update dependency antd to v3.20.2 ([#2655](https://github.com/algolia/react-instantsearch/issues/2655)) ([301c2d8](https://github.com/algolia/react-instantsearch/commit/301c2d8)) -* **deps:** update dependency antd to v3.20.3 ([#2658](https://github.com/algolia/react-instantsearch/issues/2658)) ([d078e70](https://github.com/algolia/react-instantsearch/commit/d078e70)) -* **deps:** update dependency antd to v3.20.5 ([#2686](https://github.com/algolia/react-instantsearch/issues/2686)) ([42ef821](https://github.com/algolia/react-instantsearch/commit/42ef821)) -* **deps:** update dependency antd to v3.20.6 ([#2711](https://github.com/algolia/react-instantsearch/issues/2711)) ([927fbfe](https://github.com/algolia/react-instantsearch/commit/927fbfe)) -* **deps:** update dependency antd to v3.20.7 ([#2712](https://github.com/algolia/react-instantsearch/issues/2712)) ([1830952](https://github.com/algolia/react-instantsearch/commit/1830952)) -* **deps:** update dependency antd to v3.21.1 ([#2736](https://github.com/algolia/react-instantsearch/issues/2736)) ([39a51a6](https://github.com/algolia/react-instantsearch/commit/39a51a6)) -* **deps:** update dependency antd to v3.21.2 ([#2738](https://github.com/algolia/react-instantsearch/issues/2738)) ([a7a998a](https://github.com/algolia/react-instantsearch/commit/a7a998a)) -* **deps:** update dependency antd to v3.21.4 ([#2747](https://github.com/algolia/react-instantsearch/issues/2747)) ([60012be](https://github.com/algolia/react-instantsearch/commit/60012be)) -* **deps:** update dependency antd to v3.22.0 ([#2758](https://github.com/algolia/react-instantsearch/issues/2758)) ([9cda468](https://github.com/algolia/react-instantsearch/commit/9cda468)) -* **deps:** update dependency antd to v3.22.2 ([#2791](https://github.com/algolia/react-instantsearch/issues/2791)) ([ff1f5d9](https://github.com/algolia/react-instantsearch/commit/ff1f5d9)) -* **deps:** update dependency antd to v3.23.2 ([#2814](https://github.com/algolia/react-instantsearch/issues/2814)) ([a190410](https://github.com/algolia/react-instantsearch/commit/a190410)) -* **deps:** update dependency lodash to v4.17.13 ([c4974cf](https://github.com/algolia/react-instantsearch/commit/c4974cf)) -* **deps:** update dependency lodash to v4.17.14 ([#2647](https://github.com/algolia/react-instantsearch/issues/2647)) ([a2d2dd5](https://github.com/algolia/react-instantsearch/commit/a2d2dd5)) -* **deps:** update dependency lodash to v4.17.15 ([#2684](https://github.com/algolia/react-instantsearch/issues/2684)) ([354143f](https://github.com/algolia/react-instantsearch/commit/354143f)) -* **deps:** update dependency next to v9 ([#2638](https://github.com/algolia/react-instantsearch/issues/2638)) ([d22f61d](https://github.com/algolia/react-instantsearch/commit/d22f61d)) -* **deps:** update dependency next to v9.0.1 ([#2652](https://github.com/algolia/react-instantsearch/issues/2652)) ([2c2dab9](https://github.com/algolia/react-instantsearch/commit/2c2dab9)) -* **deps:** update dependency next to v9.0.2 ([#2662](https://github.com/algolia/react-instantsearch/issues/2662)) ([6fa4c5e](https://github.com/algolia/react-instantsearch/commit/6fa4c5e)) -* **deps:** update dependency next to v9.0.3 ([#2724](https://github.com/algolia/react-instantsearch/issues/2724)) ([f51b04b](https://github.com/algolia/react-instantsearch/commit/f51b04b)) -* **deps:** update dependency next to v9.0.4 ([#2767](https://github.com/algolia/react-instantsearch/issues/2767)) ([9af9180](https://github.com/algolia/react-instantsearch/commit/9af9180)) -* **deps:** update dependency next to v9.0.5 ([#2789](https://github.com/algolia/react-instantsearch/issues/2789)) ([0a75f41](https://github.com/algolia/react-instantsearch/commit/0a75f41)) -* **deps:** update dependency qs to v6.8.0 ([#2757](https://github.com/algolia/react-instantsearch/issues/2757)) ([8bffb87](https://github.com/algolia/react-instantsearch/commit/8bffb87)) -* **deps:** update dependency react-compound-slider to v2.1.0 ([#2610](https://github.com/algolia/react-instantsearch/issues/2610)) ([3389ee5](https://github.com/algolia/react-instantsearch/commit/3389ee5)) -* **deps:** update dependency react-compound-slider to v2.2.0 ([#2649](https://github.com/algolia/react-instantsearch/issues/2649)) ([7b81af1](https://github.com/algolia/react-instantsearch/commit/7b81af1)) -* **deps:** update dependency react-native-vector-icons to v6.5.0 ([#2520](https://github.com/algolia/react-instantsearch/issues/2520)) ([5f7f5b6](https://github.com/algolia/react-instantsearch/commit/5f7f5b6)) -* **deps:** update dependency react-native-vector-icons to v6.6.0 ([#2599](https://github.com/algolia/react-instantsearch/issues/2599)) ([b6bb199](https://github.com/algolia/react-instantsearch/commit/b6bb199)) -* **deps:** update dependency react-router-dom to v5.0.1 ([#2506](https://github.com/algolia/react-instantsearch/issues/2506)) ([d762230](https://github.com/algolia/react-instantsearch/commit/d762230)) -* **highlight:** switch to index as key ([#2691](https://github.com/algolia/react-instantsearch/issues/2691)) ([17e75d1](https://github.com/algolia/react-instantsearch/commit/17e75d1)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### chore - -* **release:** 6.0.0-beta.1 ([#2861](https://github.com/algolia/react-instantsearch/issues/2861)) ([cb56ca0](https://github.com/algolia/react-instantsearch/commit/cb56ca0)), closes [#2023](https://github.com/algolia/react-instantsearch/issues/2023) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2203](https://github.com/algolia/react-instantsearch/issues/2203) [#2432](https://github.com/algolia/react-instantsearch/issues/2432) [#2444](https://github.com/algolia/react-instantsearch/issues/2444) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2454](https://github.com/algolia/react-instantsearch/issues/2454) [#2455](https://github.com/algolia/react-instantsearch/issues/2455) [#2459](https://github.com/algolia/react-instantsearch/issues/2459) [#2458](https://github.com/algolia/react-instantsearch/issues/2458) [#2460](https://github.com/algolia/react-instantsearch/issues/2460) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2446](https://github.com/algolia/react-instantsearch/issues/2446) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2466](https://github.com/algolia/react-instantsearch/issues/2466) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2555](https://github.com/algolia/react-instantsearch/issues/2555) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2349](https://github.com/algolia/react-instantsearch/issues/2349) [#2570](https://github.com/algolia/react-instantsearch/issues/2570) [#2462](https://github.com/algolia/react-instantsearch/issues/2462) [#2600](https://github.com/algolia/react-instantsearch/issues/2600) [#2468](https://github.com/algolia/react-instantsearch/issues/2468) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2621](https://github.com/algolia/react-instantsearch/issues/2621) [#2627](https://github.com/algolia/react-instantsearch/issues/2627) [#2644](https://github.com/algolia/react-instantsearch/issues/2644) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2645](https://github.com/algolia/react-instantsearch/issues/2645) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2643](https://github.com/algolia/react-instantsearch/issues/2643) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2722](https://github.com/algolia/react-instantsearch/issues/2722) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2701](https://github.com/algolia/react-instantsearch/issues/2701) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2530](https://github.com/algolia/react-instantsearch/issues/2530) [#2559](https://github.com/algolia/react-instantsearch/issues/2559) [#2560](https://github.com/algolia/react-instantsearch/issues/2560) [#2564](https://github.com/algolia/react-instantsearch/issues/2564) [#2573](https://github.com/algolia/react-instantsearch/issues/2573) [#2584](https://github.com/algolia/react-instantsearch/issues/2584) [#2611](https://github.com/algolia/react-instantsearch/issues/2611) [#2635](https://github.com/algolia/react-instantsearch/issues/2635) [#2655](https://github.com/algolia/react-instantsearch/issues/2655) [#2658](https://github.com/algolia/react-instantsearch/issues/2658) [#2686](https://github.com/algolia/react-instantsearch/issues/2686) [#2711](https://github.com/algolia/react-instantsearch/issues/2711) [#2712](https://github.com/algolia/react-instantsearch/issues/2712) [#2736](https://github.com/algolia/react-instantsearch/issues/2736) [#2738](https://github.com/algolia/react-instantsearch/issues/2738) [#2747](https://github.com/algolia/react-instantsearch/issues/2747) [#2758](https://github.com/algolia/react-instantsearch/issues/2758) [#2647](https://github.com/algolia/react-instantsearch/issues/2647) [#2684](https://github.com/algolia/react-instantsearch/issues/2684) [#2638](https://github.com/algolia/react-instantsearch/issues/2638) [#2652](https://github.com/algolia/react-instantsearch/issues/2652) [#2662](https://github.com/algolia/react-instantsearch/issues/2662) [#2724](https://github.com/algolia/react-instantsearch/issues/2724) [#2767](https://github.com/algolia/react-instantsearch/issues/2767) [#2757](https://github.com/algolia/react-instantsearch/issues/2757) [#2610](https://github.com/algolia/react-instantsearch/issues/2610) [#2649](https://github.com/algolia/react-instantsearch/issues/2649) [#2520](https://github.com/algolia/react-instantsearch/issues/2520) [#2599](https://github.com/algolia/react-instantsearch/issues/2599) [#2506](https://github.com/algolia/react-instantsearch/issues/2506) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2688](https://github.com/algolia/react-instantsearch/issues/2688) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2535](https://github.com/algolia/react-instantsearch/issues/2535) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2834](https://github.com/algolia/react-instantsearch/issues/2834) [#2845](https://github.com/algolia/react-instantsearch/issues/2845) [#2842](https://github.com/algolia/react-instantsearch/issues/2842) [#2852](https://github.com/algolia/react-instantsearch/issues/2852) [#2853](https://github.com/algolia/react-instantsearch/issues/2853) - - -### BREAKING CHANGES - -* **release:** translation will render default value if passed undefined as value - -* chore(lodash): remove imports - -* fix(translation): allow undefined value to be passed on purpose -* **release:** no longer do we allow paths like `attribute[5].something`, or other indexed forms, only `.` is allowed as special key. - -All existing tests still pass, and we never documented you could use `lodash.get` patterns other than `.`. - -* feat(get): accept array & bracked-separated string - -moved to utils at the same time - -* fix typo - -* feedback: test for undefined behaviour - -* chore(size): update expectation - -this will go down afterwards, but for now there's some more duplication - - - -# [6.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.0) (2019-08-21) - -[Migration guide](MIGRATION.md) - -### Bug Fixes - -* **react 17 compat:** upgrade RangeInput lifecycle ([#2289](https://github.com/algolia/react-instantsearch/issues/2289)) ([110b1af](https://github.com/algolia/react-instantsearch/commit/110b1af)) -* **react 17 compat:** upgrade RangeSlider lifecycle ([#2290](https://github.com/algolia/react-instantsearch/issues/2290)) ([69a7f53](https://github.com/algolia/react-instantsearch/commit/69a7f53)) -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **core:** searchState can be non-Object object ([#2722](https://github.com/algolia/react-instantsearch/issues/2722)) ([dea493c](https://github.com/algolia/react-instantsearch/commit/dea493c)), closes [#2568](https://github.com/algolia/react-instantsearch/issues/2568) -* **createConnector:** new React life cycles ([#2357](https://github.com/algolia/react-instantsearch/issues/2357)) ([fc10640](https://github.com/algolia/react-instantsearch/commit/fc10640)) -* **createInstantSearchManager:** do not trigger search on index update ([#2552](https://github.com/algolia/react-instantsearch/issues/2552)) ([e209362](https://github.com/algolia/react-instantsearch/commit/e209362)) -* **geo:** check for undefined in isEqual ([#2643](https://github.com/algolia/react-instantsearch/issues/2643)) ([a544231](https://github.com/algolia/react-instantsearch/commit/a544231)), closes [#2467](https://github.com/algolia/react-instantsearch/issues/2467) -* **geo:** remove lifecycle compat ([#2644](https://github.com/algolia/react-instantsearch/issues/2644)) ([2b2b898](https://github.com/algolia/react-instantsearch/commit/2b2b898)), closes [#2626](https://github.com/algolia/react-instantsearch/issues/2626) -* **highlight:** switch to index as key ([#2690](https://github.com/algolia/react-instantsearch/issues/2690)) ([51de682](https://github.com/algolia/react-instantsearch/commit/51de682)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **peerDependencies:** update React ([#2626](https://github.com/algolia/react-instantsearch/issues/2626)) ([6ccad49](https://github.com/algolia/react-instantsearch/commit/6ccad49)) -* **ssr:** avoid duplicate serializing ([#2726](https://github.com/algolia/react-instantsearch/issues/2726)) ([c768b1a](https://github.com/algolia/react-instantsearch/commit/c768b1a)) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### Code Refactoring - -* **lodash:** get ([#2461](https://github.com/algolia/react-instantsearch/issues/2461)) ([527b879](https://github.com/algolia/react-instantsearch/commit/527b879)) -* **lodash:** has ([#2434](https://github.com/algolia/react-instantsearch/issues/2434)) ([75a4a15](https://github.com/algolia/react-instantsearch/commit/75a4a15)) -* **lodash:** has been fully removed - -### Features - -* **autocomplete:** add queryID & position to provided hits ([#2687](https://github.com/algolia/react-instantsearch/issues/2687)) ([e453dab](https://github.com/algolia/react-instantsearch/commit/e453dab)) -* **client:** remove algoliaClient, appId & apiKey ([#2338](https://github.com/algolia/react-instantsearch/issues/2338)) ([b84a0b5](https://github.com/algolia/react-instantsearch/commit/b84a0b5)) (use searchClient exclusively now) -* **context:** migrate to new React context ([#2178](https://github.com/algolia/react-instantsearch/issues/2178)) ([0a1abea](https://github.com/algolia/react-instantsearch/commit/0a1abea)), closes [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) -* **ssr:** update the SSR API ([#2555](https://github.com/algolia/react-instantsearch/issues/2555)) ([925bdb8](https://github.com/algolia/react-instantsearch/commit/925bdb8)), closes [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) - - -### BREAKING CHANGES - -* **searchClient:** argument is the only option now. - -Previously there were three options to pass a search client: searchClient, appId & apiKey, algoliaClient. The latter two have been removed, and now only `searchClient` is accepted. This searchClient is an instance of the `algoliasearch` module: - -```js -import algoliasearch from 'algoliasearch/lite'; - -const searchClient = algoliasearch( - 'myAppId', - 'myApiKey', - { _useRequestCache: true } -); - -// ... - -``` - -If you were relying on duplicate requests not being fired when using appId & apiKey before, you need to enable the `_useRequestCache` option now. - -* **SSR:** imports have changed - -In the server, you now directly import `findResultsState`, which now requires a `searchClient` in the second argument. - -In the App, you now use a regular `InstantSearch` component. - -* **Index & InstantSearch:** Remove `root` DOM element - -These elements now are pure containers for their children, and don't add a `div` to the DOM anymore. If you were relying on those for styling, wrap the `InstantSearch` and `Index` element with a `div` with an appropriate class. - -* **Index & InstantSearch:** Remove support for `root` prop - -Since these two arguments now no longer wrap their children in an element, they no longer accept a `root` prop. - -* **Highlight:** some paths will no longer be accepted - -We only accept paths separated with a dot or bracket now, like before. It's possible that a different type of path worked undocumented, but no longer does. - -* **algoliasearch-helper:** updating to the next major version - -This library is mostly internal, but it has had a major refactor (including removing lodash). This has no impact, unless you are dealing with it using `createConnector`. See the [migration guide](https://github.com/algolia/algoliasearch-helper-js/blob/next/documentation-src/metalsmith/content/upgrade.md) for the v3 of algoliasearch-helper for more information. - -# [5.7.0](https://github.com/algolia/react-instantsearch/compare/v5.6.0...v5.7.0) (2019-06-04) - - -### Bug Fixes - -* **highlight:** allow array as "attribute" ([#2474](https://github.com/algolia/react-instantsearch/issues/2474)) ([9dc829a](https://github.com/algolia/react-instantsearch/commit/9dc829a)), closes [#2461](https://github.com/algolia/react-instantsearch/issues/2461) -* **indexUtils:** allow index with dots in it ([#2350](https://github.com/algolia/react-instantsearch/issues/2350)) ([f91906f](https://github.com/algolia/react-instantsearch/commit/f91906f)) - - -### Features - -* **voiceSearch:** add voice search widget ([#2316](https://github.com/algolia/react-instantsearch/issues/2316)) ([0e3b124](https://github.com/algolia/react-instantsearch/commit/0e3b124)) - - - -# [5.6.0](https://github.com/algolia/react-instantsearch/compare/v5.5.0...v5.6.0) (2019-05-15) - - -### Bug Fixes - -* **connectQueryRules:** avoid to throw an error with undefined values ([#2436](https://github.com/algolia/react-instantsearch/issues/2436)) ([1e18287](https://github.com/algolia/react-instantsearch/commit/1e18287)) - - -### Features - -* **infiniteHits:** add previous button ([#2296](https://github.com/algolia/react-instantsearch/issues/2296)) ([010a69a](https://github.com/algolia/react-instantsearch/commit/010a69a)) - - - -# [5.5.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0...v5.5.0) (2019-04-23) - - -### Bug Fixes - -* **createInstantSearch:** change the User-Agent to use the new specs ([#2209](https://github.com/algolia/react-instantsearch/issues/2209)) ([642ba0b](https://github.com/algolia/react-instantsearch/commit/642ba0b)) - - -### Features - -* **DOMMaps:** expose withGoogleMaps HOC [PART-1] ([#2000](https://github.com/algolia/react-instantsearch/issues/2000)) ([2ae1dea](https://github.com/algolia/react-instantsearch/commit/2ae1dea)) -* **queryRules:** add Query Rules features ([#2286](https://github.com/algolia/react-instantsearch/issues/2286)) ([3ae9c01](https://github.com/algolia/react-instantsearch/commit/3ae9c01)) -* **insights:** add insights features ([#2215](https://github.com/algolia/react-instantsearch/pull/2215)) ([961e7a7](https://github.com/algolia/react-instantsearch/commit/961e7a7)) - - - -# [5.4.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.1...v5.4.0) (2019-02-05) - - -### Bug Fixes - -* **DOMMaps:** set React & React DOM as peer deps ([#1922](https://github.com/algolia/react-instantsearch/issues/1922)) ([2f2cefd](https://github.com/algolia/react-instantsearch/commit/2f2cefd)) - - - -# [5.4.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.0...v5.4.0-beta.1) (2019-01-10) - - -### Bug Fixes - -* **deps:** sync algoliasearch version ([#1879](https://github.com/algolia/react-instantsearch/issues/1879)) ([40f9c26](https://github.com/algolia/react-instantsearch/commit/40f9c26)) -* **maps:** use stable version for peer deps ([#1887](https://github.com/algolia/react-instantsearch/issues/1887)) ([9055167](https://github.com/algolia/react-instantsearch/commit/9055167)) - - - -# [5.4.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.3.2...v5.4.0-beta.0) (2019-01-08) - - -### Features - -* **Index:** introduce `indexId` prop ([#1833](https://github.com/algolia/react-instantsearch/issues/1833)) ([ec9e0fb](https://github.com/algolia/react-instantsearch/commit/ec9e0fb)) - - - - -## [5.3.2](https://github.com/algolia/react-instantsearch/compare/v5.3.1...v5.3.2) (2018-10-30) - - -### Bug Fixes - -* **sffv:** clamp maxFacetHits to the allowed range ([#1696](https://github.com/algolia/react-instantsearch/issues/1696)) ([83ce245](https://github.com/algolia/react-instantsearch/commit/83ce245)) - - - - -## [5.3.1](https://github.com/algolia/react-instantsearch/compare/v5.3.0...v5.3.1) (2018-09-26) - - -### Bug Fixes - -* **connector:** ensure canRefine is computed on the transformed items ([#1568](https://github.com/algolia/react-instantsearch/pull/1568)) ([c95384f](https://github.com/algolia/react-instantsearch/commit/c95384f)) -* **toggle:** ensure facet is present ([#1613](https://github.com/algolia/react-instantsearch/issues/1613)) ([e914ff6](https://github.com/algolia/react-instantsearch/commit/e914ff6)) - - - - -# [5.3.0](https://github.com/algolia/react-instantsearch/compare/v5.2.3...v5.3.0) (2018-09-24) - - -### Bug Fixes - -* **SSR:** bind getSearchParmaters to the component instance ([f34cb3d](https://github.com/algolia/react-instantsearch/commit/f34cb3d)) -* **GoogleMapsLoader:** pick google maps version ([#1540](https://github.com/algolia/react-instantsearch/issues/1540)) ([b14efcf](https://github.com/algolia/react-instantsearch/commit/b14efcf)) - - -### Features - -* **connectToggleRefinement:** implement canRefine & count ([#1588](https://github.com/algolia/react-instantsearch/issues/1588)) ([40672dd](https://github.com/algolia/react-instantsearch/commit/40672dd)) - - - - -## [5.2.3](https://github.com/algolia/react-instantsearch/compare/v5.2.2...v5.2.3) (2018-08-16) - - -### Bug Fixes - -* Allow object as type for Root (closes [#1446](https://github.com/algolia/react-instantsearch/issues/1446)) ([#1461](https://github.com/algolia/react-instantsearch/issues/1461)) ([7c2317b](https://github.com/algolia/react-instantsearch/commit/7c2317b)) -* **List:** render children list only when required ([#1472](https://github.com/algolia/react-instantsearch/issues/1472)) ([9eb2cbb](https://github.com/algolia/react-instantsearch/commit/9eb2cbb)), closes [#1459](https://github.com/algolia/react-instantsearch/issues/1459) - - - - -## [5.2.2](https://github.com/algolia/react-instantsearch/compare/v5.2.1...v5.2.2) (2018-07-16) - - -Publish the previous version on `stable`. - - - - -## [5.2.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0...v5.2.1) (2018-07-16) - - -### Bug Fixes - -* **GoogleMapsLoader:** inline the import to scriptjs ([#1427](https://github.com/algolia/react-instantsearch/issues/1427)) ([8019416](https://github.com/algolia/react-instantsearch/commit/8019416)) - - - - -# [5.2.0](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.2...v5.2.0) (2018-07-04) - - -### Bug Fixes - -* **translatable:** avoid create a new function on every render ([#1383](https://github.com/algolia/react-instantsearch/issues/1383)) ([1285b3b](https://github.com/algolia/react-instantsearch/commit/1285b3b)) - - -### Features - -* **core:** export translatable ([#1351](https://github.com/algolia/react-instantsearch/issues/1351)) ([6d5a89d](https://github.com/algolia/react-instantsearch/commit/6d5a89d)) -* **maps:** add connector & widget ([#1171](https://github.com/algolia/react-instantsearch/issues/1171)) ([16e288a](https://github.com/algolia/react-instantsearch/commit/16e288a)) - - - - -# [5.2.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.1...v5.2.0-beta.2) (2018-06-19) - - -### Features - -* export highlight tags from DOM / native ([#1342](https://github.com/algolia/react-instantsearch/issues/1342)) ([28a699e](https://github.com/algolia/react-instantsearch/commit/28a699e)) -* **createInstantSearch:** enable _useRequestCache ([#1346](https://github.com/algolia/react-instantsearch/issues/1346)) ([f772600](https://github.com/algolia/react-instantsearch/commit/f772600)) -* **dom:** export create class name ([#1348](https://github.com/algolia/react-instantsearch/issues/1348)) ([9017468](https://github.com/algolia/react-instantsearch/commit/9017468)) - - - - -# [5.2.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.0...v5.2.0-beta.1) (2018-06-04) - - -### Bug Fixes - -* **dom:** publish server file ([#1305](https://github.com/algolia/react-instantsearch/issues/1305)) ([bd79693](https://github.com/algolia/react-instantsearch/commit/bd79693)) - - - - -# [5.2.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.1.0...v5.2.0-beta.0) (2018-06-04) - - -This new version introduce a complete revamp of the package structure, but it should be completely transparent for the users. - -If you have any troubles with this version please open a issue on [Github](https://github.com/algolia/react-instantsearch/issues/new), thanks! - - - - -# [5.1.0](https://github.com/algolia/react-instantsearch/compare/v5.0.3...v5.1.0) (2018-05-28) - - -### Bug Fixes - -* **connectInfiniteHits:** always set a value for previous page ([#1195](https://github.com/algolia/react-instantsearch/issues/1195)) ([4c218d5](https://github.com/algolia/react-instantsearch/commit/4c218d5)) -* **indexUtils:** avoid throw an error on cleanUp multi indices ([#1265](https://github.com/algolia/react-instantsearch/issues/1265)) ([12f5ace](https://github.com/algolia/react-instantsearch/commit/12f5ace)) - - -### Features - -* **searchClient:** Add support for custom Search Clients ([#1216](https://github.com/algolia/react-instantsearch/issues/1216)) ([174cc28](https://github.com/algolia/react-instantsearch/commit/174cc28)) - - - - -## [5.0.3](https://github.com/algolia/react-instantsearch/compare/v5.0.2...v5.0.3) (2018-04-03) - - -### Bug Fixes - -* revert dependencies as devDependencies ([#1135](https://github.com/algolia/react-instantsearch/issues/1135)) ([6b627bb](https://github.com/algolia/react-instantsearch/commit/6b627bb)) - - - - -## [5.0.2](https://github.com/algolia/react-instantsearch/compare/v5.0.1...v5.0.2) (2018-04-03) - - -### Bug Fixes - -* use lodash version of unsupported Array.{fill, find} ([#1118](https://github.com/algolia/react-instantsearch/issues/1118)) ([ea7bf42](https://github.com/algolia/react-instantsearch/commit/ea7bf42)) - - - - -## [5.0.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0...v5.0.1) (2018-03-12) - - -### Bug Fixes - -* **connectInfiniteHits:** always provide an array for hits ([#1064](https://github.com/algolia/react-instantsearch/issues/1064)) ([c75e38b](https://github.com/algolia/react-instantsearch/commit/c75e38b)) - - - - -# [5.0.0](https://github.com/algolia/react-instantsearch/compare/v4.5.2...v5.0.0) (2018-03-06) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.5.2](https://github.com/algolia/react-instantsearch/compare/v4.5.1...v4.5.2) (2018-03-06) - - -### Bug Fixes - -* **connectRange:** update default refinement propTypes ([#978](https://github.com/algolia/react-instantsearch/issues/978)) ([c065fb1](https://github.com/algolia/react-instantsearch/commit/c065fb1)) -* **IndexUtils:** avoid throw an error when cleanUp multi index ([#1019](https://github.com/algolia/react-instantsearch/issues/1019)) ([865a3c3](https://github.com/algolia/react-instantsearch/commit/865a3c3)) -* **SearchBox:** avoid to bind click on reset button ([#979](https://github.com/algolia/react-instantsearch/issues/979)) ([ea3063a](https://github.com/algolia/react-instantsearch/commit/ea3063a)) - - - - -# [5.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2018-02-06) - - -Apply features & bug fixes from [v4.5.0](#450-2018-02-06) & [v4.5.1](#451-2018-02-06) on the v5. - -See their CHANGELOG for more details. - - - - -## [4.5.1](https://github.com/algolia/react-instantsearch/compare/v4.5.0...v4.5.1) (2018-02-06) - - -### Bug Fixes - -* **StarRating:** move to 1 based instead of 0 ([#949](https://github.com/algolia/react-instantsearch/issues/949)) ([eb0152d](https://github.com/algolia/react-instantsearch/commit/eb0152d)) - - - - -# [4.5.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v4.5.0) (2018-02-06) - - -### Bug Fixes - -* **connectRange:** use the same behaviour for currentRefinement in getMetadata ([#923](https://github.com/algolia/react-instantsearch/issues/923)) ([08917b6](https://github.com/algolia/react-instantsearch/commit/08917b6)) -* **connectToggle:** use currentRefinement in metadata instead of the label ([#909](https://github.com/algolia/react-instantsearch/issues/909)) ([89cae2b](https://github.com/algolia/react-instantsearch/commit/89cae2b)) -* **StarRatings:** always show the stars below ([#929](https://github.com/algolia/react-instantsearch/issues/929)) ([22bf93a](https://github.com/algolia/react-instantsearch/commit/22bf93a)) - - -### Features - -* **connectStateResults:** expose isSearchStalled ([#933](https://github.com/algolia/react-instantsearch/issues/933)) ([f45ba27](https://github.com/algolia/react-instantsearch/commit/f45ba27)) - - - -# [5.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v5.0.0-beta.0) (2018-01-30) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.4.2](https://github.com/algolia/react-instantsearch/compare/v4.4.1...v4.4.2) (2018-01-24) - - -### Bug Fixes - -* **currentRefinements:** give access to id and index from transformItems for deduplication ([#830](https://github.com/algolia/react-instantsearch/issues/830)) ([316b8f5](https://github.com/algolia/react-instantsearch/commit/316b8f5)) -* pass maxFacetHits to SFFV ([#863](https://github.com/algolia/react-instantsearch/issues/863)) ([de23a46](https://github.com/algolia/react-instantsearch/commit/de23a46)) - - - - -## [4.4.1](https://github.com/algolia/react-instantsearch/compare/v4.4.0...v4.4.1) (2018-01-09) - - -### Bug Fixes - -* **SearchBox**: clear SearchBox without search as you type ([#802](https://github.com/algolia/react-instantsearch/issues/802)) ([c49b2b6](https://github.com/algolia/react-instantsearch/commit/c49b2b6)) -* **connectRange:** check if facet exist before access ([#797](https://github.com/algolia/react-instantsearch/issues/797)) ([6520760](https://github.com/algolia/react-instantsearch/commit/6520760)) -* **stories:** avoid to use linear-background it breaks Argos every time ([#804](https://github.com/algolia/react-instantsearch/issues/804)) ([0beded7](https://github.com/algolia/react-instantsearch/commit/0beded7)) -* **stories:** limit hits per page on Index ([#806](https://github.com/algolia/react-instantsearch/issues/806)) ([6eb14d3](https://github.com/algolia/react-instantsearch/commit/6eb14d3)) - - -### Features - -* **Index:** allow custom root ([#792](https://github.com/algolia/react-instantsearch/issues/792)) ([d793b0a](https://github.com/algolia/react-instantsearch/commit/d793b0a)) - - - - -# [4.4.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0...v4.4.0) (2018-01-03) - - -### Bug Fixes - -* **createInstantSearch:** remove the client from the Snapshot ([#749](https://github.com/algolia/react-instantsearch/issues/749)) ([700d8f4](https://github.com/algolia/react-instantsearch/commit/700d8f4)) -* refresh cache memory leak example ([#784](https://github.com/algolia/react-instantsearch/issues/784)) ([cf228ac](https://github.com/algolia/react-instantsearch/commit/cf228ac)) -* **stories:** rename InstantSearch to `` ([#789](https://github.com/algolia/react-instantsearch/issues/789)) ([05efda5](https://github.com/algolia/react-instantsearch/commit/05efda5)) - - -### Features - -* InstantSearch root props ([#770](https://github.com/algolia/react-instantsearch/issues/770)) ([2d458f8](https://github.com/algolia/react-instantsearch/commit/2d458f8)) - - - - -# [4.3.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0-beta.0...v4.3.0) (2017-12-20) - - -### Bug Fixes - -* reset page with multi index ([#665](https://github.com/algolia/react-instantsearch/issues/665)) ([865b7dc](https://github.com/algolia/react-instantsearch/commit/865b7dc)) -* track all index in the manager ([#660](https://github.com/algolia/react-instantsearch/issues/660)) ([793502b](https://github.com/algolia/react-instantsearch/commit/793502b)) - - -### Features - -* **SearchBox:** provide a loading indicator ([#544](https://github.com/algolia/react-instantsearch/issues/544)) ([189659e](https://github.com/algolia/react-instantsearch/commit/189659e)) -* **Highlight:** support array of strings ([#715](https://github.com/algolia/react-instantsearch/issues/715)) ([8e93c6a](https://github.com/algolia/react-instantsearch/commit/8e93c6a)) - - - - -# [4.3.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.2.0...v4.3.0-beta.0) (2017-11-27) - - -### Bug Fixes - -* **babelrc:** add a key for each env development, production, es ([#547](https://github.com/algolia/react-instantsearch/issues/547)) ([fa9528d](https://github.com/algolia/react-instantsearch/commit/fa9528d)) -* **localizecount:** allow localized string for count in MenuSelect ([#657](https://github.com/algolia/react-instantsearch/issues/657)) ([67ebd34](https://github.com/algolia/react-instantsearch/commit/67ebd34)) -* **react-router-example:** Properly update search query when using browser navigation ([#604](https://github.com/algolia/react-instantsearch/issues/604)) ([9ee6600](https://github.com/algolia/react-instantsearch/commit/9ee6600)) - - -### Features - -* **refreshcache:** add prop refresh to InstantSearch instance ([#619](https://github.com/algolia/react-instantsearch/issues/619)) ([19f6de0](https://github.com/algolia/react-instantsearch/commit/19f6de0)) - - - - -# [4.2.0](https://github.com/algolia/react-instantsearch/compare/v4.1.3...v4.2.0) (2017-11-02) - - -### Bug Fixes - -* **connectRange:** handle boundaries on first call ([9f14dc0](https://github.com/algolia/react-instantsearch/commit/9f14dc0)) -* **connectRange:** use refine instead of cleanUp in metadata ([#526](https://github.com/algolia/react-instantsearch/issues/526)) ([1861235](https://github.com/algolia/react-instantsearch/commit/1861235)) -* **hierarchicaMenu:** allow sorting and using limit ([fe178ed](https://github.com/algolia/react-instantsearch/commit/fe178ed)), closes [#92](https://github.com/algolia/react-instantsearch/issues/92) -* **InfiniteHits:** add disabled style to the LoadMore button ([#477](https://github.com/algolia/react-instantsearch/issues/477)) ([faba1ad](https://github.com/algolia/react-instantsearch/commit/faba1ad)) -* **Range:** handle float, allow reset and respect boundaries ([75969b8](https://github.com/algolia/react-instantsearch/commit/75969b8)) -* **RangeInput:** fix compatibility with React 16 & Panel ([3f218db](https://github.com/algolia/react-instantsearch/commit/3f218db)) -* **searchbox:** add maxlength 512 ([#542](https://github.com/algolia/react-instantsearch/issues/542)) ([5bd4033](https://github.com/algolia/react-instantsearch/commit/5bd4033)), closes [#510](https://github.com/algolia/react-instantsearch/issues/510) - - -### Features - -* **MenuSelect:** add component and connector ([cc6e0d7](https://github.com/algolia/react-instantsearch/commit/cc6e0d7)) - - - - -## [4.1.3](https://github.com/algolia/react-instantsearch/compare/v4.1.2...v4.1.3) (2017-10-09) - - -### Bug Fixes - -* **List:** remove React16 warning ([#442](https://github.com/algolia/react-instantsearch/issues/442)) ([8d6cf18](https://github.com/algolia/react-instantsearch/commit/8d6cf18)) - - -### Features - -* **connectStateResults:** add component props ([#434](https://github.com/algolia/react-instantsearch/issues/434)) ([c629b97](https://github.com/algolia/react-instantsearch/commit/c629b97)) - - - - -## [4.1.2](https://github.com/algolia/react-instantsearch/compare/v4.1.1...v4.1.2) (2017-09-26) - - -### Features - -* **Conditional:** add connectStateResults connector ([#357](https://github.com/algolia/react-instantsearch/issues/357)) ([462df5f](https://github.com/algolia/react-instantsearch/commit/462df5f)) - - - - -## [4.1.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0...v4.1.1) (2017-09-13) - - -### Bug Fixes - -* **MultiIndex:** reset page to 1 when share widgets refine (#312) ([c85a7bf](https://github.com/algolia/react-instantsearch/commit/c85a7bf)) -* **MultiIndex:** Trigger new search when `` props are updated (#318) ([bb11965](https://github.com/algolia/react-instantsearch/commit/bb11965)) - - - - -# [4.1.0](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.5...v4.1.0) (2017-08-28) - - -### Bug Fixes - -* **Highlighting:** revert breaking change (#245) ([045ee06](https://github.com/algolia/react-instantsearch/commit/045ee06)) -* **List:** adds support for any type of renderable element (#266) ([d848bb6](https://github.com/algolia/react-instantsearch/commit/d848bb6)) -* **Pagination:** fixed the offset ([3c0fff2](https://github.com/algolia/react-instantsearch/commit/3c0fff2)) -* **PoweredBy:** aria-* tags are not camelcased (#261) ([dc4a5bb](https://github.com/algolia/react-instantsearch/commit/dc4a5bb)) - - - - -# [4.1.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2017-08-08) - - -### Bug Fixes - -* **SSR:** clean SP before rendering agan (#238) ([e765886](https://github.com/algolia/react-instantsearch/commit/e765886)) - - -### Features - -* **Breadcrumb:** add a new widget & connector (#228) ([7f8f3ae](https://github.com/algolia/react-instantsearch/commit/7f8f3ae)) - - - - -# [4.1.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2017-08-03) - - -### Bug Fixes - -* **deps:** Update dependency lint-staged to version ^4.0.0 (#201) ([6867a1b](https://github.com/algolia/react-instantsearch/commit/6867a1b)) -* **nextjs/ssr:** parse `params.asPath` (#189) ([ae17da0](https://github.com/algolia/react-instantsearch/commit/ae17da0)) -* **PoweredBy:** add a label to the Algolia logo (#216) ([cd235bd](https://github.com/algolia/react-instantsearch/commit/cd235bd)) -* **react:** remove typo around `"" 2` (#220) ([f73eb04](https://github.com/algolia/react-instantsearch/commit/f73eb04)) -* **ScrollTo:** scroll to only if change triggered by the widget observed (#202) ([2d76022](https://github.com/algolia/react-instantsearch/commit/2d76022)) -* **theme:** format the count of items appearing in a refinement (#217) ([2225c24](https://github.com/algolia/react-instantsearch/commit/2225c24)) - - - - -# [4.1.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2017-07-25) - - -### Bug Fixes - -* **error:** reset error when receiving results of a query (not when sending it) (#179) ([bb12c29](https://github.com/algolia/react-instantsearch/commit/bb12c29)) -* **highlight:** wrong parsing between client and server (#183) ([2daae70](https://github.com/algolia/react-instantsearch/commit/2daae70)) -* **poweredBy:** SSR compatibility (#181) ([ec0fa8a](https://github.com/algolia/react-instantsearch/commit/ec0fa8a)) - - -### BREAKING CHANGES - -* **highlight:** We remove the timestamp present in our highlight preTag and postTag. If you were using regex to parse the -highlighting results then you'll need to adapt it as now it's only "ais-highlight". - - - - -# [4.1.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2017-07-20) - - -### Bug Fixes - -* **error:** reset error if next query is successful (#175) ([ff50a07](https://github.com/algolia/react-instantsearch/commit/ff50a07)) - - - - -# [4.1.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2017-07-12) - - - - -# [4.1.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.0.7...v4.1.0-beta.0) (2017-07-10) - - -### Bug Fixes - -* **argos:** address flakyness (#152) ([84ef8f1](https://github.com/algolia/react-instantsearch/commit/84ef8f1)) - - -### Features - -* **server-side rendering:** Add API features for server-side rendering ([86b14d1](https://github.com/algolia/react-instantsearch/commit/86b14d1)) - - - - -## [4.0.7](https://github.com/algolia/react-instantsearch/compare/v4.0.6...v4.0.7) (2017-07-06) - - -### Bug Fixes - -* **results:** revert commit that ensure hits are returned only if right indices (#149) ([df9aa25](https://github.com/algolia/react-instantsearch/commit/df9aa25)) - - - - -## [4.0.6](https://github.com/algolia/react-instantsearch/compare/v4.0.5...v4.0.6) (2017-06-29) - - -### Bug Fixes - -* **store:** delay call to listener to prevent infinite loops (#143) ([0945958](https://github.com/algolia/react-instantsearch/commit/0945958)) - - - - -## [4.0.5](https://github.com/algolia/react-instantsearch/compare/v4.0.4...v4.0.5) (2017-06-26) - - -### Bug Fixes - -* **MultiIndex:** ensure getResults return only hits matching index in the context (#136) ([124ffe6](https://github.com/algolia/react-instantsearch/commit/124ffe6)) -* **MultiIndex:** handle if namespace isn't in search state (#139) ([1aab324](https://github.com/algolia/react-instantsearch/commit/1aab324)) -* **storybook:** process CSS through autoprefixer (#138) ([62cf512](https://github.com/algolia/react-instantsearch/commit/62cf512)) - - - - -## [4.0.4](https://github.com/algolia/react-instantsearch/compare/v4.0.3...v4.0.4) (2017-06-19) - - -### Bug Fixes - -* **MultiIndex:** handle switch between mono and multi index (#132) ([e161921](https://github.com/algolia/react-instantsearch/commit/e161921)) - - - - -## [4.0.3](https://github.com/algolia/react-instantsearch/compare/v4.0.2...v4.0.3) (2017-06-14) - - -### Bug Fixes - -* **SFFV:** search status we're not inside search state (#125) ([5f3e670](https://github.com/algolia/react-instantsearch/commit/5f3e670)) - - - - -## [4.0.2](https://github.com/algolia/react-instantsearch/compare/v4.0.1...v4.0.2) (2017-05-30) - - - - -## [4.0.1](https://github.com/algolia/react-instantsearch/compare/v4.0.0...v4.0.1) (2017-05-17) - - -### Bug Fixes - -* **state:** nested attributes for faceting were not handled ([11bd122](https://github.com/algolia/react-instantsearch/commit/11bd122)) - - - - -# [4.0.0](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.6...v4.0.0) (2017-05-15) - -### Features and migration guide - -You can find all the details of the release and the migration guide from v3 to v4 here: https://discourse.algolia.com/t/react-instantsearch-v4/1329. - - - -# [4.0.0-beta.6](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2017-05-04) - - - - -# [4.0.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2017-05-02) - - -### Bug Fixes - -* **connectAutoComplete:** allow usage with hits from a single index (#75) ([8b3b358](https://github.com/algolia/react-instantsearch/commit/8b3b358)), closes [#74](https://github.com/algolia/react-instantsearch/issues/74) -* **InstantSearch:** update algoliaClient when it change (#70) ([9e97dbd](https://github.com/algolia/react-instantsearch/commit/9e97dbd)) - - - - -# [4.0.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2017-04-25) - - -### Bug Fixes - -* **MultIndex:** no need to nest hits, if those are from main index. (#56) ([86e0bd7](https://github.com/algolia/react-instantsearch/commit/86e0bd7)) - - -### Features - -* **MultiIndex:** remove the need for virtual hits when using connectAutoComplete (#45) ([7549019](https://github.com/algolia/react-instantsearch/commit/7549019)) - - - - -# [4.0.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2017-04-21) - - -### Bug Fixes - -* replace usage of Object.values (#47) ([4c79e3e](https://github.com/algolia/react-instantsearch/commit/4c79e3e)) - - - - -# [4.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2017-04-18) - - -### Bug Fixes - -* **InstantSearch:** dont fire request/onsearchStateChange when unmounting (#26) ([9a1487a](https://github.com/algolia/react-instantsearch/commit/9a1487a)) -* **MultiIndex:** derived helper were using main index specifics params (#36) ([991fea6](https://github.com/algolia/react-instantsearch/commit/991fea6)) -* **MultiIndex:** revert breaking change if no multiple index (#32) ([44f7de0](https://github.com/algolia/react-instantsearch/commit/44f7de0)) -* **util:** remove empty key was removing non object key (#29) ([9f795c7](https://github.com/algolia/react-instantsearch/commit/9f795c7)) - - -### Features - -* **Highlighter:** allow rendering to custom tag (#11) ([52a1212](https://github.com/algolia/react-instantsearch/commit/52a1212)) -* **SearchBox:** add default width and height to buttons. (#34) ([bcabf9b](https://github.com/algolia/react-instantsearch/commit/bcabf9b)) - - - - -# [4.0.0-beta.1](https://github.com/algolia/instantsearch.js/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2017-04-03) - - -### Bug Fixes - -* **SFFV:** fix wrong query behaviour with slow network (#2086) ([c251e8f](https://github.com/algolia/instantsearch.js/commit/c251e8f)), closes [#2086](https://github.com/algolia/instantsearch.js/issues/2086) - - - - -# [4.0.0-beta.0](https://github.com/algolia/instantsearch.js/compare/v3.3.0...v4.0.0-beta.0) (2017-03-28) - - -### Features - -* **multi-index:** ease multi index and auto complete ([09a4e1d](https://github.com/algolia/instantsearch.js/commit/09a4e1d)) - - -### BREAKING CHANGES - -* multi-index: * Reseting the pagination should be done at each connector level inside the "refine" function when returning the search state. -* The current page now appears inside the search state when a widget is used -* Query values are part of the items prop of the connectCurrentRefinements connector. Behaviour is unchanged, query will be filtered if clearsQuery prop is false. -* Add the index name to all the current refinements items. (not used by our widgets yet, but available if needed). - - - - -# [3.3.0](https://github.com/algolia/instantsearch.js/compare/v3.2.2-beta0...v3.3.0) (2017-03-22) - - -### Bug Fixes - -* **example:** Fix access to props in react-router example ([1417d6f](https://github.com/algolia/instantsearch.js/commit/1417d6f)) - - - - -## [3.2.2-beta0](https://github.com/algolia/instantsearch.js/compare/v3.2.1...v3.2.2-beta0) (2017-03-20) - - -### Bug Fixes - -* **InfiniteHits:** provide translation key for `Load More` (#2048) ([6130bf2](https://github.com/algolia/instantsearch.js/commit/6130bf2)) -* **SearchBox:** better mobile behaviour by default ([ea968b3](https://github.com/algolia/instantsearch.js/commit/ea968b3)) -* **example:** link to instantsearch/react (#2007) ([5e674cd](https://github.com/algolia/instantsearch.js/commit/5e674cd)) -* **recipes:** react router v4 ([de673bf](https://github.com/algolia/instantsearch.js/commit/de673bf)) - - -### Features - -* **SearchBox:** add role=search to the form (#2046) ([d1e90f3](https://github.com/algolia/instantsearch.js/commit/d1e90f3)) -* **SearchBox:** allow custom reset and submit components (#1991) ([cd303d7](https://github.com/algolia/instantsearch.js/commit/cd303d7)) -* **searchBox:** add event handling ([e267ab6](https://github.com/algolia/instantsearch.js/commit/e267ab6)), closes [#2017](https://github.com/algolia/instantsearch.js/issues/2017) - - - - -## [3.2.1](https://github.com/algolia/instantsearch.js/compare/v3.2.0...v3.2.1) (2017-02-22) - - -### Bug Fixes - -* **umd:** Add connectors to UMD build (#1988) ([23ac5e6](https://github.com/algolia/instantsearch.js/commit/23ac5e6)), closes [#1987](https://github.com/algolia/instantsearch.js/issues/1987) - - - - -# [3.2.0](https://github.com/algolia/instantsearch.js/compare/v3.1.0...v3.2.0) (2017-02-15) - - -### Bug Fixes - -* **Configure:** use props a unique source of truth (#1967) ([9d53d86](https://github.com/algolia/instantsearch.js/commit/9d53d86)) -* **SearchBox:** Safari can only have with xlinkHref (#1970) ([7ab00bd](https://github.com/algolia/instantsearch.js/commit/7ab00bd)), closes [#1968](https://github.com/algolia/instantsearch.js/issues/1968) - - -### Features - -* **MultiRange:** add an all range (#1959) ([a3dc950](https://github.com/algolia/instantsearch.js/commit/a3dc950)) - - -### BREAKING CHANGES - -* MultiRange: - MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system. - - - - -# [3.1.0](https://github.com/algolia/instantsearch.js/compare/v3.0.0...v3.1.0) (2017-02-08) - - -### Bug Fixes - -* **Configure:** call onSearchStateChange when props are updated (#1953) ([7e151db](https://github.com/algolia/instantsearch.js/commit/7e151db)), closes [#1950](https://github.com/algolia/instantsearch.js/issues/1950) -* **Configure:** trigger onSearchStateChange with the right data ([11e5af8](https://github.com/algolia/instantsearch.js/commit/11e5af8)) -* **createConnector:** updates with latest props on state change (#1951) ([cd3a82c](https://github.com/algolia/instantsearch.js/commit/cd3a82c)) - - -### Features - -* **ClearAll:** add withQuery to also clear the search query (#1958) ([c0e695b](https://github.com/algolia/instantsearch.js/commit/c0e695b)) - - - - -# [3.0.0](https://github.com/algolia/instantsearch.js/compare/v2.2.5...v3.0.0) (2017-02-06) - - -### Bug Fixes - -* ***List:** disable shortcuts in *List SearchBoxes (#1921) ([51a76ae](https://github.com/algolia/instantsearch.js/commit/51a76ae)), closes [#1920](https://github.com/algolia/instantsearch.js/issues/1920) -* **Configure:** add configure parameters in search state (#1935) ([0971330](https://github.com/algolia/instantsearch.js/commit/0971330)), closes [#1863](https://github.com/algolia/instantsearch.js/issues/1863) -* **Hits:** limit the hitComponent to be only a function (#1912) ([b3c9578](https://github.com/algolia/instantsearch.js/commit/b3c9578)) -* **Pagination:** fix and indicate when pagination is disabled ([5f20199](https://github.com/algolia/instantsearch.js/commit/5f20199)), closes [#1938](https://github.com/algolia/instantsearch.js/issues/1938) -* **StarRating:** usage with filters (#1933) ([667e9d5](https://github.com/algolia/instantsearch.js/commit/667e9d5)) -* **withSearchBox:** keep displaying searchBox when no items found (#1930) ([30de4cd](https://github.com/algolia/instantsearch.js/commit/30de4cd)) - - -### Features - -* **MultiRange:** indicate if a range has no refinements (#1926) ([80b6450](https://github.com/algolia/instantsearch.js/commit/80b6450)) -* **panel:** add a panel widget (#1889) ([594e1a1](https://github.com/algolia/instantsearch.js/commit/594e1a1)) -* **starRating:** indicate when any refinement has no effect ([c547ae5](https://github.com/algolia/instantsearch.js/commit/c547ae5)) -* **widgets:** default design for disabled states (#1929) ([31f010b](https://github.com/algolia/instantsearch.js/commit/31f010b)) - -### Migration guide - -The migration to V3.0.0 should be safe and you should do it. - -There are two breaking changes that you will need to handle in your codebase: -- Anytime you are using a connector, when there are no more items in it or no more hits, we will still call your Component. Thus you will have to handle cases like dealing with empty arrays and decide if you want to unmount or hide the widget. -- Anytime you are using a widget, when there are no more items in it or no more hits, we will still display the widget. You can then decide to hide it with CSS. - - -## [2.2.5](https://github.com/algolia/instantsearch.js/compare/v2.2.4...v2.2.5) (2017-01-23) - - -### Bug Fixes - -* **currentRefinements:** make removing a toggle refinement work ([8995e64](https://github.com/algolia/instantsearch.js/commit/8995e64)) - - - - -## [2.2.4](https://github.com/algolia/instantsearch.js/compare/v2.2.3...v2.2.4) (2017-01-20) - - -### Bug Fixes - -* **publish:** publish react-instantsearch/dist instead of root (#1884) ([64414e0](https://github.com/algolia/instantsearch.js/commit/64414e0)) - - - - -## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-01-20) - - -### Bug Fixes - -* **SFFV:** translations for searchbox were not applied (#1879) ([e9b4ee1](https://github.com/algolia/instantsearch.js/commit/e9b4ee1)) - - - - -## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-01-18) - - -### Bug Fixes - -* **react-router:** search was triggered two many times (#1840) ([25e9db5](https://github.com/algolia/instantsearch.js/commit/25e9db5)) -* **SFFV:** empty query triggered a new SFFV (#1875) ([6c8259a](https://github.com/algolia/instantsearch.js/commit/6c8259a)) - - - - -## [2.2.1](https://github.com/algolia/instantsearch.js/compare/v2.2.0...v2.2.1) (2017-01-18) - - -### Bug Fixes - -* **createInstantsearch:** fix missing props (#1867) ([8d319b5](https://github.com/algolia/instantsearch.js/commit/8d319b5)), closes [#1867](https://github.com/algolia/instantsearch.js/issues/1867) - - - - -# [2.2.0](https://github.com/algolia/instantsearch.js/compare/v2.1.0...v2.2.0) (2017-01-17) - - -### Bug Fixes - -* **clear:** clearing wasn't working with too+ same type facets selected (#1820) ([a9a2364](https://github.com/algolia/instantsearch.js/commit/a9a2364)) -* **connectSearchBox:** handle `defaultRefinement` (#1829) ([7a730e2](https://github.com/algolia/instantsearch.js/commit/7a730e2)), closes [#1826](https://github.com/algolia/instantsearch.js/issues/1826) -* **Instantsearch:** Update all props on InstantSearch (#1828) ([2ed9b49](https://github.com/algolia/instantsearch.js/commit/2ed9b49)) -* **InstantSearch:** add specific `react-instantsearch ${version}` agent (#1844) ([a1113bc](https://github.com/algolia/instantsearch.js/commit/a1113bc)) -* **SFFV:** correct propTypes and add missing default values (#1845) ([a4c1b31](https://github.com/algolia/instantsearch.js/commit/a4c1b31)) -* **test:** add missing Snippet and Highliter snapshot ([4accce5](https://github.com/algolia/instantsearch.js/commit/4accce5)) -* **widgets:** replace setImmediate use with Promise use when update is needed (#1811) ([17e2497](https://github.com/algolia/instantsearch.js/commit/17e2497)) - - -### Features - -* **Menu, connectMenu:** add search for facet values (#1822) ([a6c513e](https://github.com/algolia/instantsearch.js/commit/a6c513e)) -* **snippet:** add a snippet widget to be able to highlight snippet results (#1797) ([2aecc40](https://github.com/algolia/instantsearch.js/commit/2aecc40)) -* **widgets:** add transformItems to be able to sort and filter (#1809) ([ba539f0](https://github.com/algolia/instantsearch.js/commit/ba539f0)) - - - - -# [2.1.0](https://github.com/algolia/instantsearch.js/compare/v2.0.1...v2.1.0) (2017-01-04) - - -### Bug Fixes - -* **createInstantSearchManager:** drop outdated response (#1765) ([76c5312](https://github.com/algolia/instantsearch.js/commit/76c5312)) -* **highlight:** highlight should work even if the attribute is missing (#1791) ([5b79b15](https://github.com/algolia/instantsearch.js/commit/5b79b15)), closes [#1790](https://github.com/algolia/instantsearch.js/issues/1790) -* **InfiniteHits:** better classname to loadmore btn (#1789) ([ad2ded3](https://github.com/algolia/instantsearch.js/commit/ad2ded3)) -* **starRatings:** click on selected range doesn't unselect it (#1766) ([beacc72](https://github.com/algolia/instantsearch.js/commit/beacc72)) -* **website:** broken demo links (#1802) ([0abe2f5](https://github.com/algolia/instantsearch.js/commit/0abe2f5)) -* **widgets:** add 300px width for the default SearchBox (#1803) ([bf5d791](https://github.com/algolia/instantsearch.js/commit/bf5d791)) - - -### Features - -* **InfiniteHits:** Add class to load more button (#1787) ([416febd](https://github.com/algolia/instantsearch.js/commit/416febd)) -* **RefinementList, connectRefinementList:** allow to search for facet values ([e086a81](https://github.com/algolia/instantsearch.js/commit/e086a81)) - - - - -## [2.0.1](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.1) (2016-12-15) - - -### Bug Fixes - -* **connectRange:** when unfinite numbers are passed throw ([75bec0d](https://github.com/algolia/instantsearch.js/commit/75bec0d)) -* **react-native:** use View as a container for react-native (#1729) ([5b76f75](https://github.com/algolia/instantsearch.js/commit/5b76f75)), closes [#1730](https://github.com/algolia/instantsearch.js/issues/1730) -* **SearchBox:** autocomplete was not disabled by default (#1742) ([bc76618](https://github.com/algolia/instantsearch.js/commit/bc76618)) -* **starRating:** call createURL with the right interface (min/max) (#1747) ([f9ab9b6](https://github.com/algolia/instantsearch.js/commit/f9ab9b6)) - - - - -## [2.0.0](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.0) (2016-12-08) - -First release of `react-instantsearch` diff --git a/packages/react-instantsearch-hooks-web/README.md b/packages/react-instantsearch-hooks-web/README.md deleted file mode 100644 index 350d545458..0000000000 --- a/packages/react-instantsearch-hooks-web/README.md +++ /dev/null @@ -1,124 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [react-instantsearch-hooks-web](#react-instantsearch-hooks-web) - - [Why](#why) - - [Installation](#installation) - - [Getting started](#getting-started) - - [Documentation](#documentation) - - [Playground](#playground) - - [Contributing](#contributing) - - [License](#license) - - - -# react-instantsearch-hooks-web - -React InstantSearch Hooks Web is an open-source React library that lets you create an instant search result experience using [Algolia][algolia-website]’s search API. It is part of the InstantSearch family: - -**React InstantSearch** | [InstantSearch.js][instantsearch.js-github] | [Angular InstantSearch][instantsearch-angular-github] | [Vue InstantSearch][instantsearch-vue-github] | [InstantSearch Android][instantsearch-android-github] | [InstantSearch iOS][instantsearch-ios-github] - -## Why - -You should be using React InstantSearch Hooks Web if you want to: - -* Design search experiences with best practices -* Customize your components at will -* Follow React principles - -Note: If you are working with React Native, or otherwise do not use the DOM, check out `react-instantsearch-hooks` instead. - -## Installation - -React InstantSearch is available on the npm registry. It relies on [`algoliasearch`](https://github.com/algolia/algoliasearch-client-javascript) to communicate with Algolia APIs. - -```sh -yarn add algoliasearch react-instantsearch-hooks-web -# or -npm install algoliasearch react-instantsearch-hooks-web -``` - -## Getting started - -Using React InstantSearch Hooks Web is as simple as adding these components to your app: - -```javascript -import React from 'react'; -import ReactDOM from 'react-dom'; -import algoliasearch from 'algoliasearch/lite'; -import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-hooks-web'; - -const searchClient = algoliasearch( - 'latency', - '6be0576ff61c053d5f9a3225e2a90f76' -); - -const App = () => ( - - - - -); -``` - -

    - - Edit on CodeSandbox - -

    - -To learn more about the library, follow the [getting started guide][doc-getting-started]. - -## Documentation - -The documentation is available on [algolia.com/doc][doc]. - -## Playground - -You can get to know React InstantSearch on [this playground][doc-playground]. - -Start by [adding components][doc-getting-started] and tweaking the display. Once you get more familiar with the library, you can learn more advanced concepts in [our guides][doc-guides]. - -## Contributing - -We welcome all contributors, from casual to regular 💙 - -- **Bug report**. Is something not working as expected? [Send a bug report][contributing-bugreport]. -- **Feature request**. Would you like to add something to the library? [Send a feature request][contributing-featurerequest]. -- **Documentation**. Did you find a typo in the doc? [Open an issue][contributing-newissue] and we'll take care of it. -- **Development**. If you don't know where to start, you can check the open issues that are [tagged easy][contributing-label-easy], the [bugs][contributing-label-bug] or [chores][contributing-label-chore]. - -To start contributing to code, you need to: - -1. [Fork the project](https://help.github.com/articles/fork-a-repo/) -1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) -1. Install the dependencies: `yarn` - -Please read [our contribution process](https://github.com/algolia/instantsearch.js/blob/master/CONTRIBUTING.md) to learn more. - -## License - -React InstantSearch Hooks is [MIT licensed](../../LICENSE). - - - -[doc]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/ -[doc-getting-started]: https://www.algolia.com/doc/guides/building-search-ui/getting-started/react-hooks/ -[doc-guides]: https://www.algolia.com/doc/guides/building-search-ui/going-further/server-side-rendering/react-hooks/ -[doc-playground]: https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react-hooks/default-theme -[algolia-website]: https://www.algolia.com/ -[instantsearch.js-github]: https://github.com/algolia/instantsearch.js -[instantsearch-android-github]: https://github.com/algolia/instantsearch-android -[instantsearch-ios-github]: https://github.com/algolia/instantsearch-ios -[instantsearch-vue-github]: https://github.com/algolia/vue-instantsearch -[instantsearch-angular-github]: https://github.com/algolia/angular-instantsearch -[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch+Hooks&title=Feature%20request%3A%20 -[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 diff --git a/packages/react-instantsearch-hooks-web/package.json b/packages/react-instantsearch-hooks-web/package.json deleted file mode 100644 index 799b1be978..0000000000 --- a/packages/react-instantsearch-hooks-web/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "react-instantsearch-hooks-web", - "version": "6.47.3", - "description": "⚡ Lightning-fast search for React, by Algolia", - "source": "src/index.ts", - "types": "dist/es/index.d.ts", - "main": "dist/cjs/index.js", - "module": "dist/es/index.js", - "type": "module", - "exports": { - ".": { - "import": "./dist/es/index.js", - "require": "./dist/cjs/index.js" - } - }, - "sideEffects": false, - "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/", - "repository": { - "type": "git", - "url": "https://github.com/algolia/instantsearch.js" - }, - "author": { - "name": "Algolia, Inc.", - "url": "https://www.algolia.com" - }, - "keywords": [ - "algolia", - "components", - "fast", - "instantsearch", - "react", - "search" - ], - "files": [ - "README.md", - "dist" - ], - "scripts": { - "clean": "rm -rf dist", - "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es && yarn build:umd && yarn build:types", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet && ../../scripts/prepare-cjs.sh", - "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:umd": "BABEL_ENV=rollup rollup -c rollup.config.js", - "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", - "test:exports": "node ./test/module/is-es-module.mjs && node ./test/module/is-cjs-module.cjs" - }, - "dependencies": { - "@babel/runtime": "^7.1.2", - "instantsearch.js": "4.56.8", - "react-instantsearch-hooks": "6.47.3" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19", - "react-dom": ">= 16.8.0 < 19" - } -} diff --git a/packages/react-instantsearch-hooks-web/rollup.config.js b/packages/react-instantsearch-hooks-web/rollup.config.js deleted file mode 100644 index 368803df37..0000000000 --- a/packages/react-instantsearch-hooks-web/rollup.config.js +++ /dev/null @@ -1,80 +0,0 @@ -import babel from 'rollup-plugin-babel'; -import commonjs from 'rollup-plugin-commonjs'; -import filesize from 'rollup-plugin-filesize'; -import globals from 'rollup-plugin-node-globals'; -import resolve from 'rollup-plugin-node-resolve'; -import replace from 'rollup-plugin-replace'; -import { uglify } from 'rollup-plugin-uglify'; - -const clear = (x) => x.filter(Boolean); - -const version = process.env.VERSION || 'UNRELEASED'; -const algolia = '© Algolia, inc.'; -const link = 'https://github.com/algolia/instantsearch.js'; -const createBanner = (name) => - `/*! React InstantSearch${name} ${version} | ${algolia} | ${link} */`; - -const plugins = [ - babel({ - exclude: /node_modules|algoliasearch-helper/, - extensions: ['.js', '.ts', '.tsx'], - rootMode: 'upward', - runtimeHelpers: true, - }), - resolve({ - browser: true, - preferBuiltins: false, - extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], - }), - commonjs({ - namedExports: { - '../../node_modules/use-sync-external-store/shim/index.js': [ - 'useSyncExternalStore', - ], - }, - }), - globals(), - replace({ - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - filesize({ - showMinifiedSize: false, - showGzippedSize: true, - }), -]; - -const createConfiguration = ({ name, minify = false } = {}) => ({ - input: 'src/index.ts', - external: ['react'], - output: { - file: `dist/umd/ReactInstantSearch${name}${minify ? '.min' : ''}.js`, - name: `ReactInstantSearch${name}`, - format: 'umd', - globals: { - react: 'React', - }, - banner: createBanner(name), - sourcemap: true, - }, - plugins: plugins.concat( - clear([ - minify && - uglify({ - output: { - preamble: createBanner(name), - }, - }), - ]) - ), -}); - -export default [ - createConfiguration({ - name: 'HooksDOM', - }), - - createConfiguration({ - name: 'HooksDOM', - minify: true, - }), -]; diff --git a/packages/react-instantsearch-hooks-web/src/index.ts b/packages/react-instantsearch-hooks-web/src/index.ts deleted file mode 100644 index cf8fff457d..0000000000 --- a/packages/react-instantsearch-hooks-web/src/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from 'react-instantsearch-hooks'; -export * from './widgets'; diff --git a/packages/react-instantsearch-hooks-web/test/module/is-cjs-module.cjs b/packages/react-instantsearch-hooks-web/test/module/is-cjs-module.cjs deleted file mode 100644 index 9668df8fb9..0000000000 --- a/packages/react-instantsearch-hooks-web/test/module/is-cjs-module.cjs +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable no-console */ - -const assert = require('assert'); - -const ReactInstantSearchHooksWeb = require('react-instantsearch-hooks-web'); - -assert.ok(ReactInstantSearchHooksWeb); - -console.log('react-instantsearch-hooks-web is valid CJS'); diff --git a/packages/react-instantsearch-hooks-web/test/module/is-es-module.mjs b/packages/react-instantsearch-hooks-web/test/module/is-es-module.mjs deleted file mode 100644 index d65ecf88f6..0000000000 --- a/packages/react-instantsearch-hooks-web/test/module/is-es-module.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable no-console */ -import assert from 'assert'; - -import * as ReactInstantSearchHooksWeb from 'react-instantsearch-hooks-web'; - -assert.ok(ReactInstantSearchHooksWeb); - -console.log('react-instantsearch-hooks-web is valid ESM'); diff --git a/packages/react-instantsearch-hooks/CHANGELOG.md b/packages/react-instantsearch-hooks/CHANGELOG.md deleted file mode 100644 index 1036d686f4..0000000000 --- a/packages/react-instantsearch-hooks/CHANGELOG.md +++ /dev/null @@ -1,2060 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.47.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.2...react-instantsearch-hooks@6.47.3) (2023-07-27) - - -### Bug Fixes - -* add a future warning when the package name changes ([#5778](https://github.com/algolia/instantsearch.js/issues/5778)) ([3d22ee4](https://github.com/algolia/instantsearch.js/commit/3d22ee45e1f03a443323a371621262f1fe45e664)) -* **useInstantSearch:** deprecate `use` function ([#5781](https://github.com/algolia/instantsearch.js/issues/5781)) ([ec16c6e](https://github.com/algolia/instantsearch.js/commit/ec16c6e74cc9e364aca47d64983be32bf0cce0fe)) - - - - - -## [6.47.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.1...react-instantsearch-hooks@6.47.2) (2023-07-25) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.47.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.47.0...react-instantsearch-hooks@6.47.1) (2023-07-19) - - -### Bug Fixes - -* **instantsearch:** keep algoliasearch-helper as external dependency during build ([#5765](https://github.com/algolia/instantsearch.js/issues/5765)) ([550fefa](https://github.com/algolia/instantsearch.js/commit/550fefa1401773f38dedc20322513ae662faa25d)) - - - - - -# [6.47.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.46.0...react-instantsearch-hooks@6.47.0) (2023-07-18) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - -# [6.46.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.45.1...react-instantsearch-hooks@6.46.0) (2023-07-10) - - -### Bug Fixes - -* **url:** base createURL on UiState instead of SearchParameters ([#5696](https://github.com/algolia/instantsearch.js/issues/5696)) ([7e2c8a2](https://github.com/algolia/instantsearch.js/commit/7e2c8a295a6fc5ba36d9482f645ef55b422d5e75)), closes [#5694](https://github.com/algolia/instantsearch.js/issues/5694) - - -### Features - -* **GeoSearch:** expose useGeoSearch() hook in RISH ([#5693](https://github.com/algolia/instantsearch.js/issues/5693)) ([b951b7b](https://github.com/algolia/instantsearch.js/commit/b951b7bcafb384d990ccf02538d9bb9e248a6bba)) - - - - - -## [6.45.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.45.0...react-instantsearch-hooks@6.45.1) (2023-07-04) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -# [6.45.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.3...react-instantsearch-hooks@6.45.0) (2023-06-20) - - -### Bug Fixes - -* **dependencies:** update helper requirement ([#5676](https://github.com/algolia/instantsearch.js/issues/5676)) ([c289120](https://github.com/algolia/instantsearch.js/commit/c2891205c1125b1203b3b3db946d57e0fc4e4687)), closes [#5658](https://github.com/algolia/instantsearch.js/issues/5658) - - -### Features - -* **algoliaAgent:** track Next.js version as Algolia agent ([#5677](https://github.com/algolia/instantsearch.js/issues/5677)) ([b205ac0](https://github.com/algolia/instantsearch.js/commit/b205ac019f79699cd608d63792b8ff5a0832aa7c)) - - - - - -## [6.44.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.2...react-instantsearch-hooks@6.44.3) (2023-06-13) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.44.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.1...react-instantsearch-hooks@6.44.2) (2023-06-05) - - -### Bug Fixes - -* **hooks:** generate version for algoliaAgent in build ([#5655](https://github.com/algolia/instantsearch.js/issues/5655)) ([4d92ac4](https://github.com/algolia/instantsearch.js/commit/4d92ac4769e19e81fb55481aedc71121bef981cb)) - - - - - -## [6.44.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.44.0...react-instantsearch-hooks@6.44.1) (2023-05-30) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -# [6.44.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.43.0...react-instantsearch-hooks@6.44.0) (2023-05-16) - - -### Bug Fixes - -* **this:** ensure all functions are able to be destructured ([#5611](https://github.com/algolia/instantsearch.js/issues/5611)) ([a8b5c1e](https://github.com/algolia/instantsearch.js/commit/a8b5c1e5bbd6afac39fce523f7d7c2ec02f51153)), closes [#5589](https://github.com/algolia/instantsearch.js/issues/5589) - - -### Features - -* **instantsearch:** make root indexName optional ([#5590](https://github.com/algolia/instantsearch.js/issues/5590)) ([80f309e](https://github.com/algolia/instantsearch.js/commit/80f309ed69b61534ca118b60c9c88691e0148fca)) - - - - - -# [6.43.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.2...react-instantsearch-hooks@6.43.0) (2023-04-24) - - -### Bug Fixes - -* **lifecycle:** prevent extra network requests when unmounting multiple widgets ([#5602](https://github.com/algolia/instantsearch.js/issues/5602)) ([11458ee](https://github.com/algolia/instantsearch.js/commit/11458eee7e7f0f3e9c5f368584a16f58646b1cdd)) - - -### Features - - -* **insights:** add insights option to InstantSearch ([#5488](https://github.com/algolia/instantsearch.js/issues/5488)) ([9031573](https://github.com/algolia/instantsearch.js/commit/9031573807fa6803dcfae9f33d61b8f111f68423)) ([#5578](https://github.com/algolia/instantsearch.js/issues/5578)) ([8fb517f](https://github.com/algolia/instantsearch.js/commit/8fb517f15381ecb32ea00cf4b01a0fd5e70e1d17)) ([#5545](https://github.com/algolia/instantsearch.js/issues/5545)) ([99a0972](https://github.com/algolia/instantsearch.js/commit/99a0972663b8f3284cac3b5621571ced7a33908f)) ([#5493](https://github.com/algolia/instantsearch.js/issues/5493)) ([cff723f](https://github.com/algolia/instantsearch.js/commit/cff723fc95a90ebb2ed14c46c51ab05764835a47)) -* **insights:** always pass Algolia credentials locally ([#5554](https://github.com/algolia/instantsearch.js/issues/5554)) ([654ab81](https://github.com/algolia/instantsearch.js/commit/654ab81e1669354c249710b6756610fba35d54b4)) ([#5558](https://github.com/algolia/instantsearch.js/issues/5558)) ([82144c0](https://github.com/algolia/instantsearch.js/commit/82144c0a0b18e6b47d6f508e5c670a9de274c121)) ([#5529](https://github.com/algolia/instantsearch.js/issues/5529)) ([8537f8f](https://github.com/algolia/instantsearch.js/commit/8537f8f7a10bcaf053ff62180c082e077b1b052d)) -* **insights:** annotate events with algoliaSource ([#5580](https://github.com/algolia/instantsearch.js/issues/5580)) ([c419307](https://github.com/algolia/instantsearch.js/commit/c419307a5f7fe46d5032c9437a17c8e3dad57fe5)) -* **insights:** automatically load search-insights if not passed ([#5484](https://github.com/algolia/instantsearch.js/issues/5484)) ([a85797b](https://github.com/algolia/instantsearch.js/commit/a85797b503edc94e001c5bfb3b754db6cb556943)) -* **insights:** enable default click events on hits and infinite hits ([#5522](https://github.com/algolia/instantsearch.js/issues/5522)) ([271bd12](https://github.com/algolia/instantsearch.js/commit/271bd12e34bc55656976bb53c90282193083eb86)) ([#5527](https://github.com/algolia/instantsearch.js/issues/5527)) ([0e55821](https://github.com/algolia/instantsearch.js/commit/0e558213c807cd17d592fadec052f3d1fc692e6c)) -* **insights:** prevent potential errors ([#5487](https://github.com/algolia/instantsearch.js/issues/5487)) ([33fe510](https://github.com/algolia/instantsearch.js/commit/33fe510307e4b382a5ba1153a0eaf160420acd11)) ([#5606](https://github.com/algolia/instantsearch.js/issues/5606)) ([bdd9290](https://github.com/algolia/instantsearch.js/commit/bdd92901b59ae4e5d7311eadfbf53ed656bbaf4a)) ([#5512](https://github.com/algolia/instantsearch.js/issues/5512)) ([85dfbc9](https://github.com/algolia/instantsearch.js/commit/85dfbc9ebd722fbe6a7e1bd056950fdbcc16d8d9)) -* **metadata:** register metadata around middleware ([#5492](https://github.com/algolia/instantsearch.js/issues/5492)) ([3e72ec8](https://github.com/algolia/instantsearch.js/commit/3e72ec82894a05a071328a4802d2f764233fe005)) - - - - -## [6.42.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.1...react-instantsearch-hooks@6.42.2) (2023-04-11) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.42.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.42.0...react-instantsearch-hooks@6.42.1) (2023-03-28) - -### Features - -* **InstantSearch**: warn when an unstable search client is detected ([#5563](https://github.com/algolia/instantsearch.js/issues/5563)) ([0fcf716](https://github.com/algolia/instantsearch/commit/0fcf7162ce77246133c0d4a6ff7ea975ba17cc4c)) - - - -# [6.42.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.41.0...react-instantsearch-hooks@6.42.0) (2023-03-21) - - -### Features - -* **current-refinements:** provide indexId of refinements in transformItems ([#5546](https://github.com/algolia/instantsearch.js/issues/5546)) ([89781db](https://github.com/algolia/instantsearch.js/commit/89781db6cb1d2b8ebbc116e9bcd8a10f646e7baf)) - - - - - -# [6.41.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.1...react-instantsearch-hooks@6.41.0) (2023-03-07) - - -### Features - -* **index:** introduce setIndexUiState ([#5504](https://github.com/algolia/instantsearch.js/issues/5504)) ([c199feb](https://github.com/algolia/instantsearch.js/commit/c199febbc3381df574afbb2504edd7373b32904a)) -* **react:** export `InstantSearchApi` type ([#5518](https://github.com/algolia/instantsearch.js/issues/5518)) ([27b478f](https://github.com/algolia/instantsearch.js/commit/27b478f8f20c4e8835914cceabbdce57ff5d4650)) - - -## Bug Fixes - -* **DynamicWidgets**: prevent non-stable fallbackComponent ([#5532](https://github.com/algolia/instantsearch.js/issues/5532)) ([0625c90](https://github.com/algolia/instantsearch.js/commit/0625c90346e32b926d6ce276a4e0b13d4fa4bf6c)) - - -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.1...react-instantsearch-hooks@6.40.2) (2023-02-28) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.40.0...react-instantsearch-hooks@6.40.1) (2023-02-21) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -# [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.3...react-instantsearch-hooks@6.40.0) (2023-02-14) - - -### Features - -* Warn when not using the dedicated Next.js router ([#5432](https://github.com/algolia/instantsearch.js/issues/5432)) ([39b5859](https://github.com/algolia/instantsearch.js/commit/39b5859ba78a5e8472a80e357a35ba900c963b61)) - - -### Bug Fixes - -* Prevent issue where instantsearch instance got created twice in ssr ([#5432](https://github.com/algolia/instantsearch.js/issues/5432)) ([39b5859](https://github.com/algolia/instantsearch.js/commit/39b5859ba78a5e8472a80e357a35ba900c963b61)) - - - -## [6.39.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.2...react-instantsearch-hooks@6.39.3) (2023-02-07) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.1...react-instantsearch-hooks@6.39.2) (2023-01-30) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.39.0...react-instantsearch-hooks@6.39.1) (2023-01-26) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.3...react-instantsearch-hooks@6.39.0) (2023-01-25) - - -### Features - -* **react-instantsearch-hooks-web:** Add stats widget and ui component ([#5427](https://github.com/algolia/instantsearch.js/issues/5427)) ([d07cf0d](https://github.com/algolia/instantsearch.js/commit/d07cf0d0310bf4e49d4a4c2142b3783d9bcda79d)) -* **react-instantsearch-hooks:** Add useStats hook ([#5425](https://github.com/algolia/instantsearch.js/issues/5425)) ([772c918](https://github.com/algolia/instantsearch.js/commit/772c918f47aec183af3f1aa78c65505f70dd0088)) -* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) - - - - - -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.2...react-instantsearch-hooks@6.38.3) (2023-01-09) - - -### Bug Fixes - -* **dependencies:** update helper requirement for minor PP vulnerability ([#5417](https://github.com/algolia/instantsearch.js/issues/5417)) ([254ef00](https://github.com/algolia/instantsearch.js/commit/254ef00439a9af48be15f22b4fd9902899610226)) - - - - - -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks@6.38.1...react-instantsearch-hooks@6.38.2) (2023-01-03) - -**Note:** Version bump only for package react-instantsearch-hooks - - - - - -## [6.38.1](https://github.com/algolia/react-instantsearch/compare/v6.38.0...v6.38.1) (2022-11-08) - - -### Bug Fixes - -* **hooks:** avoid effect in useStableValue ([#3670](https://github.com/algolia/react-instantsearch/issues/3670)) ([d1f53ae](https://github.com/algolia/react-instantsearch/commit/d1f53ae815b75f13c18fd245e0403d57e7ae391c)) - - - -# [6.38.0](https://github.com/algolia/react-instantsearch/compare/v6.37.0...v6.38.0) (2022-10-25) - - -### Features - -* **getServerState:** allow users to inject renderToString ([#3658](https://github.com/algolia/react-instantsearch/issues/3658)) ([9c10449](https://github.com/algolia/react-instantsearch/commit/9c104497b9b32337f288d70a2582c41cafb13cd6)), closes [#3633](https://github.com/algolia/react-instantsearch/issues/3633) [#3618](https://github.com/algolia/react-instantsearch/issues/3618) [vercel/next.js#40067](https://github.com/vercel/next.js/issues/40067) - -* **PoweredBy:** update component logo ([#3661](https://github.com/algolia/react-instantsearch/issues/3661)) ([69c1b2a](https://github.com/algolia/react-instantsearch/commit/69c1b2acef64d972dfa6c6beb8967032119ad2d5)) - - - -# [6.37.0](https://github.com/algolia/react-instantsearch/compare/v6.36.0...v6.37.0) (2022-10-18) - - -### Features - -* **core:** support react 18 strict mode ([#3653](https://github.com/algolia/react-instantsearch/issues/3653)) ([9174806](https://github.com/algolia/react-instantsearch/commit/9174806a7997a45893a24d149027119f4a0709c3)) - - - -# [6.36.0](https://github.com/algolia/react-instantsearch/compare/v6.35.0...v6.36.0) (2022-10-04) - - -### Features - -* **HierarchicalMenu:** add css class for link of selected menu item ([#3646](https://github.com/algolia/react-instantsearch/issues/3646)) ([980ad70](https://github.com/algolia/react-instantsearch/commit/980ad70c75e970c35c11a10a534dbe3996d6c54c)) -* **useInstantSearch:** expose status & error ([#3645](https://github.com/algolia/react-instantsearch/issues/3645)) ([f436d31](https://github.com/algolia/react-instantsearch/commit/f436d31184f3f75b33a1fdaa19c665e77948df28)) - - - -# [6.35.0](https://github.com/algolia/react-instantsearch/compare/v6.34.0...v6.35.0) (2022-09-29) - - -### Features - -* **hooks-web:** introduce Translations API ([#3638](https://github.com/algolia/react-instantsearch/issues/3638)) ([63b506f](https://github.com/algolia/react-instantsearch/commit/63b506f9dbad284f45ac17210e17c4a2a8f099b6)) - -### Fixes -* **hooks-web:** when searchAsYouType=false, pressing the reset button searches (previously only reset the query) ([#3642](https://github.com/algolia/react-instantsearch/issues/3642)) ([f969deb](https://github.com/algolia/react-instantsearch/commit/f969deb05fd4f53aaa251ff88b52db2224ce0786)) - -# [6.34.0](https://github.com/algolia/react-instantsearch/compare/v6.33.0...v6.34.0) (2022-09-27) - - -### Features - -* **SearchBox:** expose formRef ([#3565](https://github.com/algolia/react-instantsearch/issues/3565)) ([1c2f46d](https://github.com/algolia/react-instantsearch/commit/1c2f46da2d1cf705cfd3946c52aef4ca9ec943d7)) - - - -# [6.33.0](https://github.com/algolia/react-instantsearch/compare/v6.32.1...v6.33.0) (2022-09-15) - - -### Bug Fixes - -* **react-native:** mark as compatible with react 18 ([#3614](https://github.com/algolia/react-instantsearch/issues/3614)) ([2a191a8](https://github.com/algolia/react-instantsearch/commit/2a191a84751127de5a3eb34b59b460a1d1bfe594)) -* **rish:** hide reset button when search is stalled in `SearchBox` ([#3617](https://github.com/algolia/react-instantsearch/issues/3617)) ([93ee9d0](https://github.com/algolia/react-instantsearch/commit/93ee9d0212893cef4842c86b7c78f285aa136be8)) - - -### Features - -* **dependencies:** update instantsearch and helper ([#3622](https://github.com/algolia/react-instantsearch/issues/3622)) ([6773ab1](https://github.com/algolia/react-instantsearch/commit/6773ab169cd74dfe1133e255daade4d57e99d9a4)) - - - -## [6.32.1](https://github.com/algolia/react-instantsearch/compare/v6.32.0...v6.32.1) (2022-08-26) - - -### Bug Fixes - -* **useInstantSearch:** prevent `results` from being `null` when first search is stalled ([#3597](https://github.com/algolia/react-instantsearch/issues/3597)) ([6f71d78](https://github.com/algolia/react-instantsearch/commit/6f71d78868fde55a3f9c4460edc337a1e99df4f9)) - - - -# [6.32.0](https://github.com/algolia/react-instantsearch/compare/v6.31.1...v6.32.0) (2022-08-22) - - -### Features - -* **SearchBox:** introduce `autoFocus` prop ([#3599](https://github.com/algolia/react-instantsearch/issues/3599)) ([99121b9](https://github.com/algolia/react-instantsearch/commit/99121b952fd002cb6dae52af41f08beed8f6c3e2)) - - - -## [6.31.1](https://github.com/algolia/react-instantsearch/compare/v6.31.0...v6.31.1) (2022-08-08) - - -### Bug Fixes - -* **hooks:** prevent widget cleanup on `` unmount ([#3590](https://github.com/algolia/react-instantsearch/issues/3590)) ([d94899d](https://github.com/algolia/react-instantsearch/commit/d94899d1264134f0cb1ca2d266a660f1fb2a588c)) - - - -# [6.31.0](https://github.com/algolia/react-instantsearch/compare/v6.30.3...v6.31.0) (2022-08-03) - - -### Features - -* **hooks:** add `searchAsYouType` option to `` ([#3585](https://github.com/algolia/react-instantsearch/issues/3585)) ([c610385](https://github.com/algolia/react-instantsearch/commit/c610385cb9688b23b3e041e31b9edd60392b341d)) - - - -## [6.30.3](https://github.com/algolia/react-instantsearch/compare/v6.30.2...v6.30.3) (2022-08-01) - - -### Bug Fixes - -* **hooks:** replace `labelText` CSS class with `label` in `` to align with InstantSearch's CSS specifications ([#3583](https://github.com/algolia/react-instantsearch/issues/3583)) ([3e030ae](https://github.com/algolia/react-instantsearch/commit/3e030aedb9f285ff449eb82589bc6fea60b160cb)) - - - -## [6.30.2](https://github.com/algolia/react-instantsearch/compare/v6.30.1...v6.30.2) (2022-07-18) - - -### Bug Fixes - -* **hooks:** type of DynamicWidgets props ([#3566](https://github.com/algolia/react-instantsearch/issues/3566)) ([612c98b](https://github.com/algolia/react-instantsearch/commit/612c98b5a77fb9037185c4b5efda8c07663dbd1a)), closes [#3563](https://github.com/algolia/react-instantsearch/issues/3563) -* **hooks:** use single instance in ([#3561](https://github.com/algolia/react-instantsearch/issues/3561)) ([4c358be](https://github.com/algolia/react-instantsearch/commit/4c358bebfc91451b1610f677f89c595d7a427f1f)) - - - -## [6.30.1](https://github.com/algolia/react-instantsearch/compare/v6.30.0...v6.30.1) (2022-07-12) - - -### Bug Fixes - -* **hooks:** provide state and results APIs from "render" event ([#3554](https://github.com/algolia/react-instantsearch/issues/3554)) ([67d4788](https://github.com/algolia/react-instantsearch/commit/67d4788ab09ec2a57b43d53e8093b8c11120b761)) -* **hooks**: update instantsearch.js dependency ([#3557](https://github.com/algolia/react-instantsearch/issues/3557)) - - - -# [6.30.0](https://github.com/algolia/react-instantsearch/compare/v6.29.0...v6.30.0) (2022-07-05) - - -### Features - -* **core:** update instantsearch and helper ([#3539](https://github.com/algolia/react-instantsearch/issues/3539)) ([0ac2c7a](https://github.com/algolia/react-instantsearch/commit/0ac2c7a3f2e2a827721f5b2b7c69c54560f8574f)) - - - -# [6.29.0](https://github.com/algolia/react-instantsearch/compare/v6.28.0...v6.29.0) (2022-06-21) - - -### Bug Fixes - -* **HierarchicalMenu:** show full hierarchical parent values ([#3521](https://github.com/algolia/react-instantsearch/issues/3521)) ([79c3890](https://github.com/algolia/react-instantsearch/commit/79c3890848175a4d70311e5c3929c902bb953c10)) - - -### Features - -* **core:** sort parameters for improved cache rate ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) -* **core:** support client.search for sffv ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) - - - -# [6.28.0](https://github.com/algolia/react-instantsearch/compare/v6.27.0...v6.28.0) (2022-06-15) - - -### Bug Fixes - -* **hooks-server:** import react server via an expression ([#3515](https://github.com/algolia/react-instantsearch/issues/3515)) ([91b96f7](https://github.com/algolia/react-instantsearch/commit/91b96f743b9315ed5ea781681b77fc7f5604ab6e)), closes [#3512](https://github.com/algolia/react-instantsearch/issues/3512) -* **hooks-web:** fix duplicated key in ([#3513](https://github.com/algolia/react-instantsearch/issues/3513)) ([fc94d80](https://github.com/algolia/react-instantsearch/commit/fc94d806daf139f58b234cdc0b450da2efe861ee)) -* **hooks:** mount widgets in SSR to retrieve HTML ([#3518](https://github.com/algolia/react-instantsearch/issues/3518)) ([aa5f9d8](https://github.com/algolia/react-instantsearch/commit/aa5f9d84ddb6e97d05e6ad1baf2c6caa23891281)) -* **types:** allow useInstantSearch to be generic ([#3508](https://github.com/algolia/react-instantsearch/issues/3508)) ([6807232](https://github.com/algolia/react-instantsearch/commit/68072324cf302801502a1b4c3d06703e57b55a97)), closes [algolia/instantsearch.js#5060](https://github.com/algolia/instantsearch.js/issues/5060) -* **types:** support React 18 types ([#3481](https://github.com/algolia/react-instantsearch/issues/3481)) ([74cf8cb](https://github.com/algolia/react-instantsearch/commit/74cf8cb9be8ff3d113b57a50e7083df0d1bc94f2)) - - -### Features - -* **hooks:** introduce `useInstantSearch()` ([#3494](https://github.com/algolia/react-instantsearch/issues/3494)) ([74d522c](https://github.com/algolia/react-instantsearch/commit/74d522c032326658f2a0b8f0001bd593e0085208)) -* **hooks:** support React 18 Strict Mode ([#3514](https://github.com/algolia/react-instantsearch/issues/3514)) ([eeb67c7](https://github.com/algolia/react-instantsearch/commit/eeb67c7b5dc08c696c46d9538f104eeceecef388)) - - - -# [6.27.0](https://github.com/algolia/react-instantsearch/compare/v6.26.0...v6.27.0) (2022-06-07) - - -### Bug Fixes - -* **hooks-web:** don't pass widget props to ui components ([#3501](https://github.com/algolia/react-instantsearch/issues/3501)) ([5bd53c1](https://github.com/algolia/react-instantsearch/commit/5bd53c128ddeeea87f75ae89eb8f2324d476c70e)), closes [#3499](https://github.com/algolia/react-instantsearch/issues/3499) -* **SearchBox-hooks:** correctly pass widget props ([#3499](https://github.com/algolia/react-instantsearch/issues/3499)) ([2cdf906](https://github.com/algolia/react-instantsearch/commit/2cdf90602b7c2c5895124ef64c389ce574154386)), closes [#3498](https://github.com/algolia/react-instantsearch/issues/3498) - - -### Features - -* **hooks:** migrate to `useSyncExternalStore()` ([#3489](https://github.com/algolia/react-instantsearch/issues/3489)) ([81bbdf2](https://github.com/algolia/react-instantsearch/commit/81bbdf28f2d28d8b0081cfd7d9e84c3e33038dd2)) -* **hooks:** upgrade to InstantSearch.js 4.41.0 ([#3502](https://github.com/algolia/react-instantsearch/issues/3502)) ([0b76792](https://github.com/algolia/react-instantsearch/commit/0b76792ea0c4e2ac9fe742810d70ba1aee2a3e79)) - - - -# [6.26.0](https://github.com/algolia/react-instantsearch/compare/v6.25.0...v6.26.0) (2022-05-19) - - -### Features - -* **hooks-web:** expose `sendEvent` to `hitComponent` ([#3476](https://github.com/algolia/react-instantsearch/issues/3476)) ([5cc18d1](https://github.com/algolia/react-instantsearch/commit/5cc18d19d9f22305f33d92e43fd0aca2a5cb949a)) -* **react-instantsearch-core:** allow widgets to set their `$$widgetType` ([#3472](https://github.com/algolia/react-instantsearch/issues/3472)) ([1c436e1](https://github.com/algolia/react-instantsearch/commit/1c436e1429ab4230bbfea7c6d2474d141f5c5c64)) - - - -# [6.25.0](https://github.com/algolia/react-instantsearch/compare/v6.24.3...v6.25.0) (2022-05-17) - - -### Bug Fixes - -* **hooks-highlight:** make sure highlight and snippet don't show html-escaped content ([#3471](https://github.com/algolia/react-instantsearch/issues/3471)) ([c18ddd2](https://github.com/algolia/react-instantsearch/commit/c18ddd25faca37d6bfa3d1c28f6fc22ec5fcf6d8)) -* **hooks-server:** remove faulty UMD build ([#3465](https://github.com/algolia/react-instantsearch/issues/3465)) ([c1ddfe4](https://github.com/algolia/react-instantsearch/commit/c1ddfe408b411551ac8524877a9d65ded8133c42)) - - -### Features - -* **dom-maps:** expose GeoSearchContext ([#3468](https://github.com/algolia/react-instantsearch/issues/3468)) ([a61ff96](https://github.com/algolia/react-instantsearch/commit/a61ff96222bfd4f6301cf93bf95e2fa18b263d3c)), closes [#3448](https://github.com/algolia/react-instantsearch/issues/3448) -* **hooks-server:** support import from React 18 ([#3464](https://github.com/algolia/react-instantsearch/issues/3464)) ([0a13867](https://github.com/algolia/react-instantsearch/commit/0a13867f7dd5a8a18e0957b2072bbde3b02d6490)), closes [#3453](https://github.com/algolia/react-instantsearch/issues/3453) -* **hooks:** make InstantSearch type generic ([#3466](https://github.com/algolia/react-instantsearch/issues/3466)) ([b0905b7](https://github.com/algolia/react-instantsearch/commit/b0905b73bed558c62eedb7ae701be20c2ebe25c9)) - - - -## [6.24.3](https://github.com/algolia/react-instantsearch/compare/v6.24.2...v6.24.3) (2022-05-10) - - -### Bug Fixes - -* **numericmenu:** include range values in comparison with minmax bounds ([#3461](https://github.com/algolia/react-instantsearch/issues/3461)) ([e4c2682](https://github.com/algolia/react-instantsearch/commit/e4c268261dc42a6aa43d985934b53c82f8b71089)) - - - -## [6.24.2](https://github.com/algolia/react-instantsearch/compare/v6.24.1...v6.24.2) (2022-05-05) - - -### Bug Fixes - -* **hooks:** prevent infinite loops from render state ([#3455](https://github.com/algolia/react-instantsearch/issues/3455)) ([1799fc9](https://github.com/algolia/react-instantsearch/commit/1799fc9f78a4a5aafb54df339c3e211ff9187748)) - - - -## [6.24.1](https://github.com/algolia/react-instantsearch/compare/v6.24.0...v6.24.1) (2022-05-03) - - -### Bug Fixes - -* **types:** export correct types for react-instantsearch-hooks-web ([#3454](https://github.com/algolia/react-instantsearch/issues/3454)) ([a863430](https://github.com/algolia/react-instantsearch/commit/a8634306621f7a05a2b3056a6db25ccf8d9eabf0)) - - - -# [6.24.0](https://github.com/algolia/react-instantsearch/compare/v6.23.4...v6.24.0) (2022-04-28) - - -### Features - -* **hooks:** expose DOM components ([#3450](https://github.com/algolia/react-instantsearch/issues/3450)) ([5732e3d](https://github.com/algolia/react-instantsearch/commit/5732e3de732275911f94b26ba9e2c4165bdf77e7)) -* **hooks:** remove experimental warning ([#3446](https://github.com/algolia/react-instantsearch/issues/3446)) ([84c99fe](https://github.com/algolia/react-instantsearch/commit/84c99fe91d6906a877bec620b44c61d762f0ea57)) - - - -## [6.23.4](https://github.com/algolia/react-instantsearch/compare/v6.23.3...v6.23.4) (2022-04-21) - - -### Bug Fixes - -* **hooks:** forbid importing from instantsearch.js root path ([#3437](https://github.com/algolia/react-instantsearch/issues/3437)) ([82ef9ea](https://github.com/algolia/react-instantsearch/commit/82ef9eaaec42bc54f15796b5b031a8656330a45c)) -* **packages:** correctly mark peer dependency ([#3439](https://github.com/algolia/react-instantsearch/issues/3439)) ([51e8818](https://github.com/algolia/react-instantsearch/commit/51e8818fce224819230c8bf6dea2a08d71d9be29)), closes [#3428](https://github.com/algolia/react-instantsearch/issues/3428) - - - -## [6.23.3](https://github.com/algolia/react-instantsearch/compare/v6.23.2...v6.23.3) (2022-04-05) - - -### Bug Fixes - -* **facets:** show raw value in currentRefinements ([#3420](https://github.com/algolia/react-instantsearch/issues/3420)) ([1199ce6](https://github.com/algolia/react-instantsearch/commit/1199ce6bd4152e4b54bd2ee0e1f0c9d81021c7d5)), closes [#3412](https://github.com/algolia/react-instantsearch/issues/3412) -* **multi-index:** correctly set `searching` prop in multi-index result states ([#3419](https://github.com/algolia/react-instantsearch/issues/3419)) ([7f8e97e](https://github.com/algolia/react-instantsearch/commit/7f8e97e31b3dd5e49d3febef673f41f7dfa6d45d)) - - - -## [6.23.2](https://github.com/algolia/react-instantsearch/compare/v6.23.1...v6.23.2) (2022-04-04) - - -### Bug Fixes - -* **refinements:** use escaped value for refining ([#3412](https://github.com/algolia/react-instantsearch/issues/3412)) ([f2f5f6c](https://github.com/algolia/react-instantsearch/commit/f2f5f6cbfaed48a5c494daeb8789e8deebc64293)) -* support React 18 as peer dependency ([#3411](https://github.com/algolia/react-instantsearch/issues/3411)) ([38eb5a6](https://github.com/algolia/react-instantsearch/commit/38eb5a6a8fe92cb763a25f452bea78b189a6a82a)) - - -## [6.23.1](https://algolia/compare/v6.23.0...v6.23.1) (2022-03-30) - - -### Bug Fixes - -* **hooks:** compute initial search parameters from widget ([#3399](https://algolia/issues/3399)) ([b4bd933](https://algolia/commits/b4bd93358598bdc77a1aa858252e6eee23441345)) - - - -# [6.23.0](https://algolia/compare/v6.22.0...v6.23.0) (2022-03-23) - - -### Bug Fixes - -* **ssr:** perform initial multi-index search using a single request ([#3385](https://algolia/issues/3385)) ([b96809e](https://algolia/commits/b96809e5748d298350890647956cb7adbbb55650)) - - -### Features - -* **hooks:** allow additional widget properties to be passed from hooks ([#3359](https://algolia/issues/3359)) ([a047be4](https://algolia/commits/a047be45c7fce7ee28f7d6f61d2fbfa79e3ed2d0)) -* **hooks:** allow useHits and useInfiniteHit to be generic ([#3364](https://algolia/issues/3364)) ([8e66ad3](https://algolia/commits/8e66ad3ad587197c4811c60a5cab475137ca5afb)) -* **hooks:** mark initial results as "artificial" ([#3384](https://algolia/issues/3384)) ([937efdc](https://algolia/commits/937efdc71bae1d99270f8ecb5c5c9c501b3d7769)) - - - -# [6.22.0](https://github.com/algolia/react-instantsearch/compare/v6.21.1...v6.22.0) (2022-02-01) - - -### Bug Fixes - -* **hooks:** enable pause on exceptions on warning ([#3283](https://github.com/algolia/react-instantsearch/issues/3283)) ([ce3a6c3](https://github.com/algolia/react-instantsearch/commit/ce3a6c3f2700a05ae54a91278fd23fa64a97d733)) - - -### Features - -* **hooks:** introduce `useBreadcrumb()` ([#3245](https://github.com/algolia/react-instantsearch/issues/3245)) ([5bfbaaf](https://github.com/algolia/react-instantsearch/commit/5bfbaaf746e7632968ac9b30b73357bcb0b37e91)) - - - -## [6.21.1](https://github.com/algolia/react-instantsearch/compare/v6.21.0...v6.21.1) (2022-01-25) - - -### Bug Fixes - -* **hooks:** apply initial search parameters in useConnector ([#3276](https://github.com/algolia/react-instantsearch/issues/3276)) ([f85d679](https://github.com/algolia/react-instantsearch/commit/f85d6794c31eac61521fd8fc16b75673f02ed75b)) - - - -# [6.21.0](https://github.com/algolia/react-instantsearch/compare/v6.20.0...v6.21.0) (2022-01-24) - - -### Features - -* **hooks-server:** load data twice in the case of dynamic widget usage ([#3259](https://github.com/algolia/react-instantsearch/issues/3259)) ([9b4903b](https://github.com/algolia/react-instantsearch/commit/9b4903b2ea73d9d7e33729b87d9d55990e64312c)) -* **server:** load data twice in the case of dynamic widget usage ([#3268](https://github.com/algolia/react-instantsearch/issues/3268)) ([91cd085](https://github.com/algolia/react-instantsearch/commit/91cd085f9a323ed6b872f3a098f561007a72d0d2)), closes [/github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js#L14-L16](https://github.com//github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js/issues/L14-L16) - - - -# [6.20.0](https://github.com/algolia/react-instantsearch/compare/v6.19.0...v6.20.0) (2022-01-18) - - -### Bug Fixes - -* **hooks:** allow importing via require ([#3257](https://github.com/algolia/react-instantsearch/issues/3257)) ([6aa80b3](https://github.com/algolia/react-instantsearch/commit/6aa80b3647567199c3df1b90a07d708b223ce1fd)) - - -### Features - -* **hooks:** implement `useClearRefinements()` ([#3256](https://github.com/algolia/react-instantsearch/issues/3256)) ([930b83d](https://github.com/algolia/react-instantsearch/commit/930b83df4c4bbccbc3118f6ea1001f6a30a3d464)), closes [#3252](https://github.com/algolia/react-instantsearch/issues/3252) -* **hooks:** introduce `` ([#3261](https://github.com/algolia/react-instantsearch/issues/3261)) ([3527b94](https://github.com/algolia/react-instantsearch/commit/3527b9422de48a4a6b4bd752bd643e01cd5011d8)) -* **hooks:** introduce `usePoweredBy()` ([#3251](https://github.com/algolia/react-instantsearch/issues/3251)) ([a97230b](https://github.com/algolia/react-instantsearch/commit/a97230b89e3ba1df9bf2d21a6a9f9a70b45f41b8)) -* **hooks:** introduce `useToggleRefinement()` ([#3248](https://github.com/algolia/react-instantsearch/issues/3248)) ([a561c09](https://github.com/algolia/react-instantsearch/commit/a561c090a268e1c6ca1fa2d5bf72263cc47aa273)) - - - -# [6.19.0](https://github.com/algolia/react-instantsearch/compare/v6.18.0...v6.19.0) (2022-01-05) - - -### Features - -* **hooks:** bundle as es-module ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) -* **dependencies:** update to latest algoliasearch-helper ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) - - - -# [6.18.0](https://github.com/algolia/react-instantsearch/compare/v6.17.0...v6.18.0) (2021-12-16) - - -### Features - -* **dynamicWidgets:** send facets * and maxValuesPerFacet by default ([#3242](https://github.com/algolia/react-instantsearch/issues/3242)) ([c071776](https://github.com/algolia/react-instantsearch/commit/c07177670ac30dced55250774654e8b2a77b6739)) -* **hooks:** introduce `useNumericMenu()` ([#3237](https://github.com/algolia/react-instantsearch/issues/3237)) ([e3056c9](https://github.com/algolia/react-instantsearch/commit/e3056c9e2c64b5afafb7a736599a5cbf6137575b)) -* **hooks:** introduce `useInfiniteHits()` ([#3224](https://github.com/algolia/react-instantsearch/issues/3224)) ([177ec56](https://github.com/algolia/react-instantsearch/commit/177ec56af274670c2bf8599ba104b5544979bbe8)) - - - -# [6.17.0](https://github.com/algolia/react-instantsearch/compare/v6.16.0...v6.17.0) (2021-12-08) - - -### Bug Fixes - -* **hooks:** throw invariant violations in production ([#3217](https://github.com/algolia/react-instantsearch/issues/3217)) ([6d3f99c](https://github.com/algolia/react-instantsearch/commit/6d3f99ca91f470ee742ddc55e95f57b1f1801d7b)) - - -### Features - -* **hooks:** introduce `useMenu()` ([#3197](https://github.com/algolia/react-instantsearch/issues/3197)) ([15d1cc9](https://github.com/algolia/react-instantsearch/commit/15d1cc993437b111cd5a32f43ee1d2065c639ed4)) -* **hooks:** introduce `useRange()` ([#3198](https://github.com/algolia/react-instantsearch/issues/3198)) ([df1f1c8](https://github.com/algolia/react-instantsearch/commit/df1f1c8109dc684e74d3aee1bf0359f2a0e1b9f4)) -* **hooks:** introduce `` ([#3216](https://github.com/algolia/react-instantsearch/issues/3216)) ([d99aea6](https://github.com/algolia/react-instantsearch/commit/d99aea6cfe9dea86ae6b98ee3762373f4b3843f1)) -* **hooks:** introduce `useDynamicWidgets()` ([#3210](https://github.com/algolia/react-instantsearch/issues/3210)) ([29c2ea2](https://github.com/algolia/react-instantsearch/commit/29c2ea22b91a39d9eb40a044ae9aab85f2612db8)) -* **hooks:** introduce `useQueryRules()` ([#3212](https://github.com/algolia/react-instantsearch/issues/3212)) ([3ef1e1e](https://github.com/algolia/react-instantsearch/commit/3ef1e1e4116b3e58b2c2134d0c60fbb9f40c1501)) -* **hooks:** introduce SSR support ([#3221](https://github.com/algolia/react-instantsearch/issues/3221)) ([0a6b3ec](https://github.com/algolia/react-instantsearch/commit/0a6b3ec61942ad3849c6f078e21b3328679bffff)) -* **hooks:** introduce `useCurrentRefinements()` ([#3222](https://github.com/algolia/react-instantsearch/issues/3222)) ([7ebd8c3](https://github.com/algolia/react-instantsearch/commit/7ebd8c3da8c17b0bd7e0f8deab633b98fa052e7f)) - - - -# [6.16.0](https://github.com/algolia/react-instantsearch/compare/v6.15.0...v6.16.0) (2021-11-22) - - -### Bug Fixes - -* **PoweredBy:** support environments with `window` but no `location` ([#3186](https://github.com/algolia/react-instantsearch/issues/3186)) ([22ff23b](https://github.com/algolia/react-instantsearch/commit/22ff23b67554683567393114c2f53cacec44f4a6)) - - -### Features - -* **DynamicWidgets:** release as stable ([#3090](https://github.com/algolia/react-instantsearch/issues/3090)) ([a4a1d9e](https://github.com/algolia/react-instantsearch/commit/a4a1d9e032b31c611d5d73fdda3a03ad705f5c68)) -* **hooks:** introduce `usePagination()` ([#3182](https://github.com/algolia/react-instantsearch/issues/3182)) ([d8b1b86](https://github.com/algolia/react-instantsearch/commit/d8b1b867bb598e801f1350e81b4a4220a8e528d7)) -* **hooks:** introduce `useSortBy()` ([#3190](https://github.com/algolia/react-instantsearch/issues/3190)) ([5cce33b](https://github.com/algolia/react-instantsearch/commit/5cce33b48032548fed76b592ee0201e3c42fc3c4)) -* **hooks:** introduce `useHierarchicalMenu()` ([#3199](https://github.com/algolia/react-instantsearch/issues/3199)) ([b347061](https://github.com/algolia/react-instantsearch/commit/b3470611b962ef55c55576c65a6307abc54e5efd)) - - - -# [6.15.0](https://github.com/algolia/react-instantsearch/compare/v6.14.0...v6.15.0) (2021-10-27) - - -### Bug Fixes - -* **metadata:** stricter detection of user agent ([#3184](https://github.com/algolia/react-instantsearch/issues/3184)) ([994c8ae](https://github.com/algolia/react-instantsearch/commit/994c8ae055fc23a1a067d111d2f4727b1c7bf8ca)) - - -### Features - -* **hooks:** introduce `useConfigure()` ([#3181](https://github.com/algolia/react-instantsearch/issues/3181)) ([aa2eb9b](https://github.com/algolia/react-instantsearch/commit/aa2eb9baec6335f8a3523ee8b9b761a217cfc734)) - - - -# [6.14.0](https://github.com/algolia/react-instantsearch/compare/v6.13.0...v6.14.0) (2021-10-26) - - -### Features - -* **dependencies:** update algoliasearch-helper ([#3176](https://github.com/algolia/react-instantsearch/issues/3176)) ([a8708a3](https://github.com/algolia/react-instantsearch/commit/a8708a33f31632000bc827b076539b1cca7adf6f)) -* **metadata:** expose widget information ([#3145](https://github.com/algolia/react-instantsearch/issues/3145)) ([46cddf8](https://github.com/algolia/react-instantsearch/commit/46cddf8fcc0291beaa34b04da7aaaa7f2566e52e)) - - - -# [6.13.0](https://github.com/algolia/react-instantsearch/compare/v6.12.1...v6.13.0) (2021-10-19) - -This is the initial release of the experimental **React InstantSearch Hooks** package. Check out the [**Getting Started**](https://github.com/algolia/react-instantsearch/blob/e8d72cb1c7c45300ef7c273f1f163beb6dc57622/packages/react-instantsearch-hooks/README.md#getting-started) guide. - -### Bug Fixes - -- **core:** accept objects for `hitComponent` ([#3087](https://github.com/algolia/react-instantsearch/issues/3087)) ([4ae23d4](https://github.com/algolia/react-instantsearch/commit/4ae23d432a01ccbefff1fcdc865120aeca4d3efc)) - -### Features - -- **hooks:** add InstantSearch and Index components ([#3133](https://github.com/algolia/react-instantsearch/issues/3133)) ([8e3370d](https://github.com/algolia/react-instantsearch/commit/8e3370ddb7d5e42b8b9a5ff6a1e4255490de7dbe)) -- **hooks:** bootstrap Core package ([#3132](https://github.com/algolia/react-instantsearch/issues/3132)) ([d459e62](https://github.com/algolia/react-instantsearch/commit/d459e62f5cae4c98427ab302531873f5ee23d149)) -- **hooks:** display experimental warning ([#3149](https://github.com/algolia/react-instantsearch/issues/3149)) ([623577c](https://github.com/algolia/react-instantsearch/commit/623577c50cd0c04cd87f719edafdcfa04b5527b6)) -- **hooks:** export types ([#3159](https://github.com/algolia/react-instantsearch/issues/3159)) ([182348b](https://github.com/algolia/react-instantsearch/commit/182348b4a901823a7a41aee5d2b3bdc025cce48f)) -- **hooks:** expose `displayName` on Contexts ([#3168](https://github.com/algolia/react-instantsearch/issues/3168)) ([dafd3c6](https://github.com/algolia/react-instantsearch/commit/dafd3c66d05fbec09ebf907209ac25f55804e6f5)) -- **hooks:** friendly error when using Hooks with Core ([#3150](https://github.com/algolia/react-instantsearch/issues/3150)) ([d547ccf](https://github.com/algolia/react-instantsearch/commit/d547ccf7951299e2f6b1771e02fce052696ff65a)) -- **hooks:** introduce `useConnector()` ([#3137](https://github.com/algolia/react-instantsearch/issues/3137)) ([53e8afd](https://github.com/algolia/react-instantsearch/commit/53e8afd093b9950351467a16b82d528207ac34d2)) -- **hooks:** introduce `useHits()` ([#3147](https://github.com/algolia/react-instantsearch/issues/3147)) ([cc25cff](https://github.com/algolia/react-instantsearch/commit/cc25cff06e5ec216cba40fb8261372bc327001b6)) -- **hooks:** introduce `useRefinementList()` ([#3152](https://github.com/algolia/react-instantsearch/issues/3152)) ([0385cd9](https://github.com/algolia/react-instantsearch/commit/0385cd971635a8423ad687fab451d0778358389e)) -- **hooks:** introduce `useSearchBox()` ([#3146](https://github.com/algolia/react-instantsearch/issues/3146)) ([0d2c7f9](https://github.com/algolia/react-instantsearch/commit/0d2c7f9bd25b88cf725a1babd3b228ac804644c7)) -- **hooks:** trigger single network request on load ([#3167](https://github.com/algolia/react-instantsearch/issues/3167)) ([ff1ea49](https://github.com/algolia/react-instantsearch/commit/ff1ea49079a7800fd61ba99ceeb74b9f513eb99d)) -- **hooks:** type `useConnector()` return as render state ([#3169](https://github.com/algolia/react-instantsearch/issues/3169)) ([a801468](https://github.com/algolia/react-instantsearch/commit/a80146860164a092d2c90ee0aa4fcef88d5b675f)) -- **hooks:** update GitHub bug reports link ([#3157](https://github.com/algolia/react-instantsearch/issues/3157)) ([568b5c8](https://github.com/algolia/react-instantsearch/commit/568b5c83849a3927417907706656c3835163f216)) - - - -## [6.12.1](https://github.com/algolia/react-instantsearch/compare/v6.12.0...v6.12.1) (2021-08-02) - - -### Bug Fixes - -* **server side rendering:** return a value from mock currentRefinement/metadata ([#3078](https://github.com/algolia/react-instantsearch/issues/3078)) ([09f802b](https://github.com/algolia/react-instantsearch/commit/09f802b)) - - - -# [6.12.0](https://github.com/algolia/react-instantsearch/compare/v6.11.2...v6.12.0) (2021-07-06) - - -### Bug Fixes - -* **HitsPerPage:** Adds id prop to HitsPerPage, Select components ([#3072](https://github.com/algolia/react-instantsearch/issues/3072)) ([bc75d75](https://github.com/algolia/react-instantsearch/commit/bc75d75)) -* **MenuSelect:** Adds id prop to MenuSelect ([#3073](https://github.com/algolia/react-instantsearch/issues/3073)) ([fddaaef](https://github.com/algolia/react-instantsearch/commit/fddaaef)) -* **SearchBox:** Adds inputId prop to SearchBox ([#3074](https://github.com/algolia/react-instantsearch/issues/3074)) ([a05f6a4](https://github.com/algolia/react-instantsearch/commit/a05f6a4)) -* **SortBy:** Adds `id` prop to `SortBy`, `Select` components ([#3068](https://github.com/algolia/react-instantsearch/issues/3068)) ([1f2797f](https://github.com/algolia/react-instantsearch/commit/1f2797f)) - - -### Features - -* **DynamicWidgets:** add implementation ([#3056](https://github.com/algolia/react-instantsearch/issues/3056)) ([691ef87](https://github.com/algolia/react-instantsearch/commit/691ef87)) -* **facets:** add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu ([#3067](https://github.com/algolia/react-instantsearch/issues/3067)) ([731d9ba](https://github.com/algolia/react-instantsearch/commit/731d9ba)) - - - -## [6.11.2](https://github.com/algolia/react-instantsearch/compare/v6.11.1...v6.11.2) (2021-06-28) - - -### Bug Fixes - -* **maps:** leave zoom in place if the bounds did not change ([#3050](https://github.com/algolia/react-instantsearch/issues/3050)) ([c430598](https://github.com/algolia/react-instantsearch/commit/c430598)) - - - -## [6.11.1](https://github.com/algolia/react-instantsearch/compare/v6.11.0...v6.11.1) (2021-06-09) - - -### Bug Fixes - -* **RefinementList:** prevent searchable component to refine on empty list ([#3059](https://github.com/algolia/react-instantsearch/issues/3059)) ([04f3644](https://github.com/algolia/react-instantsearch/commit/04f3644)) - - - -# [6.11.0](https://github.com/algolia/react-instantsearch/compare/v6.10.3...v6.11.0) (2021-05-04) - - -### Features - -* **connectNumericMenu:** add support for floating point values ([#3047](https://github.com/algolia/react-instantsearch/issues/3047)) ([091bf57](https://github.com/algolia/react-instantsearch/commit/091bf57)) - - - -## [6.10.3](https://github.com/algolia/react-instantsearch/compare/v6.10.2...v6.10.3) (2021-03-03) - - -### Bug Fixes - -* **RelevantSort:** Rename `SmartSort` widget to `RelevantSort` ([#3026](https://github.com/algolia/react-instantsearch/issues/3026)) ([47d11bf](https://github.com/algolia/react-instantsearch/commit/47d11bf)) - - - -## [6.10.2](https://github.com/algolia/react-instantsearch/compare/v6.10.1...v6.10.2) (2021-03-03) - - -### Bug Fixes - -* **infiniteHits:** fix stale hits issue ([#3021](https://github.com/algolia/react-instantsearch/issues/3021)) ([a9a29c7](https://github.com/algolia/react-instantsearch/commit/a9a29c7)) - - - -## [6.10.1](https://github.com/algolia/react-instantsearch/compare/v6.10.0...v6.10.1) (2021-03-02) - - -### Bug Fixes - -* **SmartSort:** make `textComponent` and `buttonTextComponent` optional ([#3014](https://github.com/algolia/react-instantsearch/issues/3014)) ([682ee6d](https://github.com/algolia/react-instantsearch/commit/682ee6d)) - - - -# [6.10.0](https://github.com/algolia/react-instantsearch/compare/v6.9.0...v6.10.0) (2021-02-23) - - -### Bug Fixes - -* **infiniteHits:** do not cache the cached hits ([#3011](https://github.com/algolia/react-instantsearch/issues/3011)) ([b56f5f7](https://github.com/algolia/react-instantsearch/commit/b56f5f7)) - - -### Features - -* **smartSort:** add widget ([#3009](https://github.com/algolia/react-instantsearch/issues/3009)) ([4cc8412](https://github.com/algolia/react-instantsearch/commit/4cc8412)), closes [#3010](https://github.com/algolia/react-instantsearch/issues/3010) - - - -# [6.9.0](https://github.com/algolia/react-instantsearch/compare/v6.8.3...v6.9.0) (2021-02-03) - - -### Features - -* **answers:** add `EXPERIMENTAL_Answers` widget ([#2996](https://github.com/algolia/react-instantsearch/issues/2996)) ([55e4191](https://github.com/algolia/react-instantsearch/commit/55e4191)), closes [#3005](https://github.com/algolia/react-instantsearch/issues/3005) - - - -## [6.8.3](https://github.com/algolia/react-instantsearch/compare/v6.8.2...v6.8.3) (2021-01-22) - - -### Bug Fixes - -* upgrade prop-types dependency to 15.6+ ([#3003](https://github.com/algolia/react-instantsearch/issues/3003)) ([fc03496](https://github.com/algolia/react-instantsearch/commit/fc03496)) - - - -## [6.8.2](https://github.com/algolia/react-instantsearch/compare/v6.8.1...v6.8.2) (2020-10-21) - - -### Bug Fixes - -* **ssr:** provide metadata default value ([0a2f34c](https://github.com/algolia/react-instantsearch/commit/0a2f34c)) - - - -## [6.8.1](https://github.com/algolia/react-instantsearch/compare/v6.8.0...v6.8.1) (2020-10-14) - - -### Bug Fixes - -* **ssr:** hydrate metadata with a value ([9249c19](https://github.com/algolia/react-instantsearch/commit/9249c19)) - - - -# [6.8.0](https://github.com/algolia/react-instantsearch/compare/v6.7.0...v6.8.0) (2020-10-14) - - -### Bug Fixes - -* **ssr:** make sure metadata is available on initial render ([#2973](https://github.com/algolia/react-instantsearch/issues/2973)) ([be43b65](https://github.com/algolia/react-instantsearch/commit/be43b65)), closes [#2972](https://github.com/algolia/react-instantsearch/issues/2972) -* add missing dependencies ([#2975](https://github.com/algolia/react-instantsearch/issues/2975)) ([22ecb3c](https://github.com/algolia/react-instantsearch/commit/22ecb3c)) -* **ConfigureRelatedItems:** support nested attributes ([#2967](https://github.com/algolia/react-instantsearch/issues/2967)) ([86dfe86](https://github.com/algolia/react-instantsearch/commit/86dfe86)) -* **ssr:** allow "params" to be optional in custom clients ([#2961](https://github.com/algolia/react-instantsearch/issues/2961)) ([c3e3d2e](https://github.com/algolia/react-instantsearch/commit/c3e3d2e)), closes [#2958](https://github.com/algolia/react-instantsearch/issues/2958) - - - -# [6.7.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.7.0) (2020-07-20) - - -### Bug Fixes - -* **core:** appending successful index search results by returning new object reference ([#2953](https://github.com/algolia/react-instantsearch/issues/2953)) ([0a711a7](https://github.com/algolia/react-instantsearch/commit/0a711a7)) -* **ssr:** remove second instance of "query" in the response "params" for SSR ([#2945](https://github.com/algolia/react-instantsearch/issues/2945)) ([bf837c5](https://github.com/algolia/react-instantsearch/commit/bf837c5)), closes [#2941](https://github.com/algolia/react-instantsearch/issues/2941) - - -### Features - -* **infinite-hits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.6.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.6.0) (2020-06-15) - - -### Features - -* **infiniteHits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.5.0](https://github.com/algolia/react-instantsearch/compare/v6.4.0...v6.5.0) (2020-05-18) - - -### Bug Fixes - -* **connectQueryRules:** fix crash when using connectQueryRules with multiple indexes ([#2903](https://github.com/algolia/react-instantsearch/issues/2903)) ([c66d612](https://github.com/algolia/react-instantsearch/commit/c66d612)) -* **core:** fix maximum call stack size exceeded ([#2926](https://github.com/algolia/react-instantsearch/issues/2926)) ([7e883df](https://github.com/algolia/react-instantsearch/commit/7e883df)) - - -### Features - -* **SearchBox:** provide input element ref ([#2913](https://github.com/algolia/react-instantsearch/issues/2913)) ([b41bff2](https://github.com/algolia/react-instantsearch/commit/b41bff2)) - - - -# [6.4.0](https://github.com/algolia/react-instantsearch/compare/v6.3.0...v6.4.0) (2020-03-18) - - -### Bug Fixes - -* **deps:** fix "too much recursion" error with circular deps ([#2899](https://github.com/algolia/react-instantsearch/issues/2899)) ([c5f27a1](https://github.com/algolia/react-instantsearch/commit/c5f27a1)) - - - -# [6.3.0](https://github.com/algolia/react-instantsearch/compare/v6.2.0...v6.3.0) (2020-01-30) - - -### Features - -* **algoliasearch:** add support for algoliasearch v4 ([#2890](https://github.com/algolia/react-instantsearch/issues/2890)) ([c6c7382](https://github.com/algolia/react-instantsearch/commit/c6c7382)) - - - -# [6.2.0](https://github.com/algolia/react-instantsearch/compare/v6.1.0...v6.2.0) (2020-01-20) - - -### Bug Fixes - -* **deps:** update dependency algoliasearch to v3.35.1 ([#2802](https://github.com/algolia/react-instantsearch/issues/2802)) ([cfb91f0](https://github.com/algolia/react-instantsearch/commit/cfb91f0)) -* **widgets:** rename `ExperimentalConfigureRelatedItems` compon… ([#2891](https://github.com/algolia/react-instantsearch/issues/2891)) ([b910df2](https://github.com/algolia/react-instantsearch/commit/b910df2)) - - -### Features - -* **insights:** add getInsightsAnonymousUserToken helper ([#2887](https://github.com/algolia/react-instantsearch/issues/2887)) ([b5fe4f7](https://github.com/algolia/react-instantsearch/commit/b5fe4f7)) -* **widgets:** introduce `ConfigureRelatedItems` as experimental ([#2880](https://github.com/algolia/react-instantsearch/issues/2880)) ([923cd43](https://github.com/algolia/react-instantsearch/commit/923cd43)) - - - -# [6.1.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0...v6.1.0) (2019-12-17) - - -### Bug Fixes - -* **connectNumericMenu:** support numeric refinement 0 ([#2882](https://github.com/algolia/react-instantsearch/issues/2882)) ([30bd9fd](https://github.com/algolia/react-instantsearch/commit/30bd9fd)) -* **deps:** update dependency next to v9.1.1 ([9d49d33](https://github.com/algolia/react-instantsearch/commit/9d49d33)) -* **helper:** rely on stable version of algoliasearch-helper ([#2871](https://github.com/algolia/react-instantsearch/issues/2871)) ([e3531a1](https://github.com/algolia/react-instantsearch/commit/e3531a1)) - - -### Features - -* **insights:** show an error when 'clickAnalytics: true' is missing. ([#2877](https://github.com/algolia/react-instantsearch/issues/2877)) ([621656a](https://github.com/algolia/react-instantsearch/commit/621656a)) -* **voice:** add additionalQueryParameters ([#2366](https://github.com/algolia/react-instantsearch/issues/2366)) ([3a45b2c](https://github.com/algolia/react-instantsearch/commit/3a45b2c)) - - - -# [6.0.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.2...v6.0.0) (2019-10-28) - - - -# [6.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2019-10-25) - - -### Bug Fixes - -* serialize cache value on hydrate ([#2862](https://github.com/algolia/react-instantsearch/issues/2862)) ([3319665](https://github.com/algolia/react-instantsearch/commit/3319665)), closes [#2828](https://github.com/algolia/react-instantsearch/issues/2828) - - - -# [6.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.1) (2019-10-18) - - -### Bug Fixes - -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **deps:** update dependency antd to v3.19.3 ([#2530](https://github.com/algolia/react-instantsearch/issues/2530)) ([73636c5](https://github.com/algolia/react-instantsearch/commit/73636c5)) -* **deps:** update dependency antd to v3.19.4 ([#2559](https://github.com/algolia/react-instantsearch/issues/2559)) ([c3e8267](https://github.com/algolia/react-instantsearch/commit/c3e8267)) -* **deps:** update dependency antd to v3.19.5 ([#2560](https://github.com/algolia/react-instantsearch/issues/2560)) ([72efd31](https://github.com/algolia/react-instantsearch/commit/72efd31)) -* **deps:** update dependency antd to v3.19.6 ([#2564](https://github.com/algolia/react-instantsearch/issues/2564)) ([654f986](https://github.com/algolia/react-instantsearch/commit/654f986)) -* **deps:** update dependency antd to v3.19.7 ([#2573](https://github.com/algolia/react-instantsearch/issues/2573)) ([7e963ad](https://github.com/algolia/react-instantsearch/commit/7e963ad)) -* **deps:** update dependency antd to v3.19.8 ([#2584](https://github.com/algolia/react-instantsearch/issues/2584)) ([34dd9b2](https://github.com/algolia/react-instantsearch/commit/34dd9b2)) -* **deps:** update dependency antd to v3.20.0 ([#2611](https://github.com/algolia/react-instantsearch/issues/2611)) ([b976c67](https://github.com/algolia/react-instantsearch/commit/b976c67)) -* **deps:** update dependency antd to v3.20.1 ([#2635](https://github.com/algolia/react-instantsearch/issues/2635)) ([792ad9c](https://github.com/algolia/react-instantsearch/commit/792ad9c)) -* **deps:** update dependency antd to v3.20.2 ([#2655](https://github.com/algolia/react-instantsearch/issues/2655)) ([301c2d8](https://github.com/algolia/react-instantsearch/commit/301c2d8)) -* **deps:** update dependency antd to v3.20.3 ([#2658](https://github.com/algolia/react-instantsearch/issues/2658)) ([d078e70](https://github.com/algolia/react-instantsearch/commit/d078e70)) -* **deps:** update dependency antd to v3.20.5 ([#2686](https://github.com/algolia/react-instantsearch/issues/2686)) ([42ef821](https://github.com/algolia/react-instantsearch/commit/42ef821)) -* **deps:** update dependency antd to v3.20.6 ([#2711](https://github.com/algolia/react-instantsearch/issues/2711)) ([927fbfe](https://github.com/algolia/react-instantsearch/commit/927fbfe)) -* **deps:** update dependency antd to v3.20.7 ([#2712](https://github.com/algolia/react-instantsearch/issues/2712)) ([1830952](https://github.com/algolia/react-instantsearch/commit/1830952)) -* **deps:** update dependency antd to v3.21.1 ([#2736](https://github.com/algolia/react-instantsearch/issues/2736)) ([39a51a6](https://github.com/algolia/react-instantsearch/commit/39a51a6)) -* **deps:** update dependency antd to v3.21.2 ([#2738](https://github.com/algolia/react-instantsearch/issues/2738)) ([a7a998a](https://github.com/algolia/react-instantsearch/commit/a7a998a)) -* **deps:** update dependency antd to v3.21.4 ([#2747](https://github.com/algolia/react-instantsearch/issues/2747)) ([60012be](https://github.com/algolia/react-instantsearch/commit/60012be)) -* **deps:** update dependency antd to v3.22.0 ([#2758](https://github.com/algolia/react-instantsearch/issues/2758)) ([9cda468](https://github.com/algolia/react-instantsearch/commit/9cda468)) -* **deps:** update dependency antd to v3.22.2 ([#2791](https://github.com/algolia/react-instantsearch/issues/2791)) ([ff1f5d9](https://github.com/algolia/react-instantsearch/commit/ff1f5d9)) -* **deps:** update dependency antd to v3.23.2 ([#2814](https://github.com/algolia/react-instantsearch/issues/2814)) ([a190410](https://github.com/algolia/react-instantsearch/commit/a190410)) -* **deps:** update dependency lodash to v4.17.13 ([c4974cf](https://github.com/algolia/react-instantsearch/commit/c4974cf)) -* **deps:** update dependency lodash to v4.17.14 ([#2647](https://github.com/algolia/react-instantsearch/issues/2647)) ([a2d2dd5](https://github.com/algolia/react-instantsearch/commit/a2d2dd5)) -* **deps:** update dependency lodash to v4.17.15 ([#2684](https://github.com/algolia/react-instantsearch/issues/2684)) ([354143f](https://github.com/algolia/react-instantsearch/commit/354143f)) -* **deps:** update dependency next to v9 ([#2638](https://github.com/algolia/react-instantsearch/issues/2638)) ([d22f61d](https://github.com/algolia/react-instantsearch/commit/d22f61d)) -* **deps:** update dependency next to v9.0.1 ([#2652](https://github.com/algolia/react-instantsearch/issues/2652)) ([2c2dab9](https://github.com/algolia/react-instantsearch/commit/2c2dab9)) -* **deps:** update dependency next to v9.0.2 ([#2662](https://github.com/algolia/react-instantsearch/issues/2662)) ([6fa4c5e](https://github.com/algolia/react-instantsearch/commit/6fa4c5e)) -* **deps:** update dependency next to v9.0.3 ([#2724](https://github.com/algolia/react-instantsearch/issues/2724)) ([f51b04b](https://github.com/algolia/react-instantsearch/commit/f51b04b)) -* **deps:** update dependency next to v9.0.4 ([#2767](https://github.com/algolia/react-instantsearch/issues/2767)) ([9af9180](https://github.com/algolia/react-instantsearch/commit/9af9180)) -* **deps:** update dependency next to v9.0.5 ([#2789](https://github.com/algolia/react-instantsearch/issues/2789)) ([0a75f41](https://github.com/algolia/react-instantsearch/commit/0a75f41)) -* **deps:** update dependency qs to v6.8.0 ([#2757](https://github.com/algolia/react-instantsearch/issues/2757)) ([8bffb87](https://github.com/algolia/react-instantsearch/commit/8bffb87)) -* **deps:** update dependency react-compound-slider to v2.1.0 ([#2610](https://github.com/algolia/react-instantsearch/issues/2610)) ([3389ee5](https://github.com/algolia/react-instantsearch/commit/3389ee5)) -* **deps:** update dependency react-compound-slider to v2.2.0 ([#2649](https://github.com/algolia/react-instantsearch/issues/2649)) ([7b81af1](https://github.com/algolia/react-instantsearch/commit/7b81af1)) -* **deps:** update dependency react-native-vector-icons to v6.5.0 ([#2520](https://github.com/algolia/react-instantsearch/issues/2520)) ([5f7f5b6](https://github.com/algolia/react-instantsearch/commit/5f7f5b6)) -* **deps:** update dependency react-native-vector-icons to v6.6.0 ([#2599](https://github.com/algolia/react-instantsearch/issues/2599)) ([b6bb199](https://github.com/algolia/react-instantsearch/commit/b6bb199)) -* **deps:** update dependency react-router-dom to v5.0.1 ([#2506](https://github.com/algolia/react-instantsearch/issues/2506)) ([d762230](https://github.com/algolia/react-instantsearch/commit/d762230)) -* **highlight:** switch to index as key ([#2691](https://github.com/algolia/react-instantsearch/issues/2691)) ([17e75d1](https://github.com/algolia/react-instantsearch/commit/17e75d1)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### chore - -* **release:** 6.0.0-beta.1 ([#2861](https://github.com/algolia/react-instantsearch/issues/2861)) ([cb56ca0](https://github.com/algolia/react-instantsearch/commit/cb56ca0)), closes [#2023](https://github.com/algolia/react-instantsearch/issues/2023) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2203](https://github.com/algolia/react-instantsearch/issues/2203) [#2432](https://github.com/algolia/react-instantsearch/issues/2432) [#2444](https://github.com/algolia/react-instantsearch/issues/2444) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2454](https://github.com/algolia/react-instantsearch/issues/2454) [#2455](https://github.com/algolia/react-instantsearch/issues/2455) [#2459](https://github.com/algolia/react-instantsearch/issues/2459) [#2458](https://github.com/algolia/react-instantsearch/issues/2458) [#2460](https://github.com/algolia/react-instantsearch/issues/2460) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2446](https://github.com/algolia/react-instantsearch/issues/2446) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2466](https://github.com/algolia/react-instantsearch/issues/2466) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2555](https://github.com/algolia/react-instantsearch/issues/2555) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2349](https://github.com/algolia/react-instantsearch/issues/2349) [#2570](https://github.com/algolia/react-instantsearch/issues/2570) [#2462](https://github.com/algolia/react-instantsearch/issues/2462) [#2600](https://github.com/algolia/react-instantsearch/issues/2600) [#2468](https://github.com/algolia/react-instantsearch/issues/2468) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2621](https://github.com/algolia/react-instantsearch/issues/2621) [#2627](https://github.com/algolia/react-instantsearch/issues/2627) [#2644](https://github.com/algolia/react-instantsearch/issues/2644) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2645](https://github.com/algolia/react-instantsearch/issues/2645) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2643](https://github.com/algolia/react-instantsearch/issues/2643) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2722](https://github.com/algolia/react-instantsearch/issues/2722) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2701](https://github.com/algolia/react-instantsearch/issues/2701) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2530](https://github.com/algolia/react-instantsearch/issues/2530) [#2559](https://github.com/algolia/react-instantsearch/issues/2559) [#2560](https://github.com/algolia/react-instantsearch/issues/2560) [#2564](https://github.com/algolia/react-instantsearch/issues/2564) [#2573](https://github.com/algolia/react-instantsearch/issues/2573) [#2584](https://github.com/algolia/react-instantsearch/issues/2584) [#2611](https://github.com/algolia/react-instantsearch/issues/2611) [#2635](https://github.com/algolia/react-instantsearch/issues/2635) [#2655](https://github.com/algolia/react-instantsearch/issues/2655) [#2658](https://github.com/algolia/react-instantsearch/issues/2658) [#2686](https://github.com/algolia/react-instantsearch/issues/2686) [#2711](https://github.com/algolia/react-instantsearch/issues/2711) [#2712](https://github.com/algolia/react-instantsearch/issues/2712) [#2736](https://github.com/algolia/react-instantsearch/issues/2736) [#2738](https://github.com/algolia/react-instantsearch/issues/2738) [#2747](https://github.com/algolia/react-instantsearch/issues/2747) [#2758](https://github.com/algolia/react-instantsearch/issues/2758) [#2647](https://github.com/algolia/react-instantsearch/issues/2647) [#2684](https://github.com/algolia/react-instantsearch/issues/2684) [#2638](https://github.com/algolia/react-instantsearch/issues/2638) [#2652](https://github.com/algolia/react-instantsearch/issues/2652) [#2662](https://github.com/algolia/react-instantsearch/issues/2662) [#2724](https://github.com/algolia/react-instantsearch/issues/2724) [#2767](https://github.com/algolia/react-instantsearch/issues/2767) [#2757](https://github.com/algolia/react-instantsearch/issues/2757) [#2610](https://github.com/algolia/react-instantsearch/issues/2610) [#2649](https://github.com/algolia/react-instantsearch/issues/2649) [#2520](https://github.com/algolia/react-instantsearch/issues/2520) [#2599](https://github.com/algolia/react-instantsearch/issues/2599) [#2506](https://github.com/algolia/react-instantsearch/issues/2506) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2688](https://github.com/algolia/react-instantsearch/issues/2688) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2535](https://github.com/algolia/react-instantsearch/issues/2535) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2834](https://github.com/algolia/react-instantsearch/issues/2834) [#2845](https://github.com/algolia/react-instantsearch/issues/2845) [#2842](https://github.com/algolia/react-instantsearch/issues/2842) [#2852](https://github.com/algolia/react-instantsearch/issues/2852) [#2853](https://github.com/algolia/react-instantsearch/issues/2853) - - -### BREAKING CHANGES - -* **release:** translation will render default value if passed undefined as value - -* chore(lodash): remove imports - -* fix(translation): allow undefined value to be passed on purpose -* **release:** no longer do we allow paths like `attribute[5].something`, or other indexed forms, only `.` is allowed as special key. - -All existing tests still pass, and we never documented you could use `lodash.get` patterns other than `.`. - -* feat(get): accept array & bracked-separated string - -moved to utils at the same time - -* fix typo - -* feedback: test for undefined behaviour - -* chore(size): update expectation - -this will go down afterwards, but for now there's some more duplication - - - -# [6.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.0) (2019-08-21) - -[Migration guide](MIGRATION.md) - -### Bug Fixes - -* **react 17 compat:** upgrade RangeInput lifecycle ([#2289](https://github.com/algolia/react-instantsearch/issues/2289)) ([110b1af](https://github.com/algolia/react-instantsearch/commit/110b1af)) -* **react 17 compat:** upgrade RangeSlider lifecycle ([#2290](https://github.com/algolia/react-instantsearch/issues/2290)) ([69a7f53](https://github.com/algolia/react-instantsearch/commit/69a7f53)) -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **core:** searchState can be non-Object object ([#2722](https://github.com/algolia/react-instantsearch/issues/2722)) ([dea493c](https://github.com/algolia/react-instantsearch/commit/dea493c)), closes [#2568](https://github.com/algolia/react-instantsearch/issues/2568) -* **createConnector:** new React life cycles ([#2357](https://github.com/algolia/react-instantsearch/issues/2357)) ([fc10640](https://github.com/algolia/react-instantsearch/commit/fc10640)) -* **createInstantSearchManager:** do not trigger search on index update ([#2552](https://github.com/algolia/react-instantsearch/issues/2552)) ([e209362](https://github.com/algolia/react-instantsearch/commit/e209362)) -* **geo:** check for undefined in isEqual ([#2643](https://github.com/algolia/react-instantsearch/issues/2643)) ([a544231](https://github.com/algolia/react-instantsearch/commit/a544231)), closes [#2467](https://github.com/algolia/react-instantsearch/issues/2467) -* **geo:** remove lifecycle compat ([#2644](https://github.com/algolia/react-instantsearch/issues/2644)) ([2b2b898](https://github.com/algolia/react-instantsearch/commit/2b2b898)), closes [#2626](https://github.com/algolia/react-instantsearch/issues/2626) -* **highlight:** switch to index as key ([#2690](https://github.com/algolia/react-instantsearch/issues/2690)) ([51de682](https://github.com/algolia/react-instantsearch/commit/51de682)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **peerDependencies:** update React ([#2626](https://github.com/algolia/react-instantsearch/issues/2626)) ([6ccad49](https://github.com/algolia/react-instantsearch/commit/6ccad49)) -* **ssr:** avoid duplicate serializing ([#2726](https://github.com/algolia/react-instantsearch/issues/2726)) ([c768b1a](https://github.com/algolia/react-instantsearch/commit/c768b1a)) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### Code Refactoring - -* **lodash:** get ([#2461](https://github.com/algolia/react-instantsearch/issues/2461)) ([527b879](https://github.com/algolia/react-instantsearch/commit/527b879)) -* **lodash:** has ([#2434](https://github.com/algolia/react-instantsearch/issues/2434)) ([75a4a15](https://github.com/algolia/react-instantsearch/commit/75a4a15)) -* **lodash:** has been fully removed - -### Features - -* **autocomplete:** add queryID & position to provided hits ([#2687](https://github.com/algolia/react-instantsearch/issues/2687)) ([e453dab](https://github.com/algolia/react-instantsearch/commit/e453dab)) -* **client:** remove algoliaClient, appId & apiKey ([#2338](https://github.com/algolia/react-instantsearch/issues/2338)) ([b84a0b5](https://github.com/algolia/react-instantsearch/commit/b84a0b5)) (use searchClient exclusively now) -* **context:** migrate to new React context ([#2178](https://github.com/algolia/react-instantsearch/issues/2178)) ([0a1abea](https://github.com/algolia/react-instantsearch/commit/0a1abea)), closes [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) -* **ssr:** update the SSR API ([#2555](https://github.com/algolia/react-instantsearch/issues/2555)) ([925bdb8](https://github.com/algolia/react-instantsearch/commit/925bdb8)), closes [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) - - -### BREAKING CHANGES - -* **searchClient:** argument is the only option now. - -Previously there were three options to pass a search client: searchClient, appId & apiKey, algoliaClient. The latter two have been removed, and now only `searchClient` is accepted. This searchClient is an instance of the `algoliasearch` module: - -```js -import algoliasearch from 'algoliasearch/lite'; - -const searchClient = algoliasearch( - 'myAppId', - 'myApiKey', - { _useRequestCache: true } -); - -// ... - -``` - -If you were relying on duplicate requests not being fired when using appId & apiKey before, you need to enable the `_useRequestCache` option now. - -* **SSR:** imports have changed - -In the server, you now directly import `findResultsState`, which now requires a `searchClient` in the second argument. - -In the App, you now use a regular `InstantSearch` component. - -* **Index & InstantSearch:** Remove `root` DOM element - -These elements now are pure containers for their children, and don't add a `div` to the DOM anymore. If you were relying on those for styling, wrap the `InstantSearch` and `Index` element with a `div` with an appropriate class. - -* **Index & InstantSearch:** Remove support for `root` prop - -Since these two arguments now no longer wrap their children in an element, they no longer accept a `root` prop. - -* **Highlight:** some paths will no longer be accepted - -We only accept paths separated with a dot or bracket now, like before. It's possible that a different type of path worked undocumented, but no longer does. - -* **algoliasearch-helper:** updating to the next major version - -This library is mostly internal, but it has had a major refactor (including removing lodash). This has no impact, unless you are dealing with it using `createConnector`. See the [migration guide](https://github.com/algolia/algoliasearch-helper-js/blob/next/documentation-src/metalsmith/content/upgrade.md) for the v3 of algoliasearch-helper for more information. - -# [5.7.0](https://github.com/algolia/react-instantsearch/compare/v5.6.0...v5.7.0) (2019-06-04) - - -### Bug Fixes - -* **highlight:** allow array as "attribute" ([#2474](https://github.com/algolia/react-instantsearch/issues/2474)) ([9dc829a](https://github.com/algolia/react-instantsearch/commit/9dc829a)), closes [#2461](https://github.com/algolia/react-instantsearch/issues/2461) -* **indexUtils:** allow index with dots in it ([#2350](https://github.com/algolia/react-instantsearch/issues/2350)) ([f91906f](https://github.com/algolia/react-instantsearch/commit/f91906f)) - - -### Features - -* **voiceSearch:** add voice search widget ([#2316](https://github.com/algolia/react-instantsearch/issues/2316)) ([0e3b124](https://github.com/algolia/react-instantsearch/commit/0e3b124)) - - - -# [5.6.0](https://github.com/algolia/react-instantsearch/compare/v5.5.0...v5.6.0) (2019-05-15) - - -### Bug Fixes - -* **connectQueryRules:** avoid to throw an error with undefined values ([#2436](https://github.com/algolia/react-instantsearch/issues/2436)) ([1e18287](https://github.com/algolia/react-instantsearch/commit/1e18287)) - - -### Features - -* **infiniteHits:** add previous button ([#2296](https://github.com/algolia/react-instantsearch/issues/2296)) ([010a69a](https://github.com/algolia/react-instantsearch/commit/010a69a)) - - - -# [5.5.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0...v5.5.0) (2019-04-23) - - -### Bug Fixes - -* **createInstantSearch:** change the User-Agent to use the new specs ([#2209](https://github.com/algolia/react-instantsearch/issues/2209)) ([642ba0b](https://github.com/algolia/react-instantsearch/commit/642ba0b)) - - -### Features - -* **DOMMaps:** expose withGoogleMaps HOC [PART-1] ([#2000](https://github.com/algolia/react-instantsearch/issues/2000)) ([2ae1dea](https://github.com/algolia/react-instantsearch/commit/2ae1dea)) -* **queryRules:** add Query Rules features ([#2286](https://github.com/algolia/react-instantsearch/issues/2286)) ([3ae9c01](https://github.com/algolia/react-instantsearch/commit/3ae9c01)) -* **insights:** add insights features ([#2215](https://github.com/algolia/react-instantsearch/pull/2215)) ([961e7a7](https://github.com/algolia/react-instantsearch/commit/961e7a7)) - - - -# [5.4.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.1...v5.4.0) (2019-02-05) - - -### Bug Fixes - -* **DOMMaps:** set React & React DOM as peer deps ([#1922](https://github.com/algolia/react-instantsearch/issues/1922)) ([2f2cefd](https://github.com/algolia/react-instantsearch/commit/2f2cefd)) - - - -# [5.4.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.0...v5.4.0-beta.1) (2019-01-10) - - -### Bug Fixes - -* **deps:** sync algoliasearch version ([#1879](https://github.com/algolia/react-instantsearch/issues/1879)) ([40f9c26](https://github.com/algolia/react-instantsearch/commit/40f9c26)) -* **maps:** use stable version for peer deps ([#1887](https://github.com/algolia/react-instantsearch/issues/1887)) ([9055167](https://github.com/algolia/react-instantsearch/commit/9055167)) - - - -# [5.4.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.3.2...v5.4.0-beta.0) (2019-01-08) - - -### Features - -* **Index:** introduce `indexId` prop ([#1833](https://github.com/algolia/react-instantsearch/issues/1833)) ([ec9e0fb](https://github.com/algolia/react-instantsearch/commit/ec9e0fb)) - - - - -## [5.3.2](https://github.com/algolia/react-instantsearch/compare/v5.3.1...v5.3.2) (2018-10-30) - - -### Bug Fixes - -* **sffv:** clamp maxFacetHits to the allowed range ([#1696](https://github.com/algolia/react-instantsearch/issues/1696)) ([83ce245](https://github.com/algolia/react-instantsearch/commit/83ce245)) - - - - -## [5.3.1](https://github.com/algolia/react-instantsearch/compare/v5.3.0...v5.3.1) (2018-09-26) - - -### Bug Fixes - -* **connector:** ensure canRefine is computed on the transformed items ([#1568](https://github.com/algolia/react-instantsearch/pull/1568)) ([c95384f](https://github.com/algolia/react-instantsearch/commit/c95384f)) -* **toggle:** ensure facet is present ([#1613](https://github.com/algolia/react-instantsearch/issues/1613)) ([e914ff6](https://github.com/algolia/react-instantsearch/commit/e914ff6)) - - - - -# [5.3.0](https://github.com/algolia/react-instantsearch/compare/v5.2.3...v5.3.0) (2018-09-24) - - -### Bug Fixes - -* **SSR:** bind getSearchParmaters to the component instance ([f34cb3d](https://github.com/algolia/react-instantsearch/commit/f34cb3d)) -* **GoogleMapsLoader:** pick google maps version ([#1540](https://github.com/algolia/react-instantsearch/issues/1540)) ([b14efcf](https://github.com/algolia/react-instantsearch/commit/b14efcf)) - - -### Features - -* **connectToggleRefinement:** implement canRefine & count ([#1588](https://github.com/algolia/react-instantsearch/issues/1588)) ([40672dd](https://github.com/algolia/react-instantsearch/commit/40672dd)) - - - - -## [5.2.3](https://github.com/algolia/react-instantsearch/compare/v5.2.2...v5.2.3) (2018-08-16) - - -### Bug Fixes - -* Allow object as type for Root (closes [#1446](https://github.com/algolia/react-instantsearch/issues/1446)) ([#1461](https://github.com/algolia/react-instantsearch/issues/1461)) ([7c2317b](https://github.com/algolia/react-instantsearch/commit/7c2317b)) -* **List:** render children list only when required ([#1472](https://github.com/algolia/react-instantsearch/issues/1472)) ([9eb2cbb](https://github.com/algolia/react-instantsearch/commit/9eb2cbb)), closes [#1459](https://github.com/algolia/react-instantsearch/issues/1459) - - - - -## [5.2.2](https://github.com/algolia/react-instantsearch/compare/v5.2.1...v5.2.2) (2018-07-16) - - -Publish the previous version on `stable`. - - - - -## [5.2.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0...v5.2.1) (2018-07-16) - - -### Bug Fixes - -* **GoogleMapsLoader:** inline the import to scriptjs ([#1427](https://github.com/algolia/react-instantsearch/issues/1427)) ([8019416](https://github.com/algolia/react-instantsearch/commit/8019416)) - - - - -# [5.2.0](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.2...v5.2.0) (2018-07-04) - - -### Bug Fixes - -* **translatable:** avoid create a new function on every render ([#1383](https://github.com/algolia/react-instantsearch/issues/1383)) ([1285b3b](https://github.com/algolia/react-instantsearch/commit/1285b3b)) - - -### Features - -* **core:** export translatable ([#1351](https://github.com/algolia/react-instantsearch/issues/1351)) ([6d5a89d](https://github.com/algolia/react-instantsearch/commit/6d5a89d)) -* **maps:** add connector & widget ([#1171](https://github.com/algolia/react-instantsearch/issues/1171)) ([16e288a](https://github.com/algolia/react-instantsearch/commit/16e288a)) - - - - -# [5.2.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.1...v5.2.0-beta.2) (2018-06-19) - - -### Features - -* export highlight tags from DOM / native ([#1342](https://github.com/algolia/react-instantsearch/issues/1342)) ([28a699e](https://github.com/algolia/react-instantsearch/commit/28a699e)) -* **createInstantSearch:** enable _useRequestCache ([#1346](https://github.com/algolia/react-instantsearch/issues/1346)) ([f772600](https://github.com/algolia/react-instantsearch/commit/f772600)) -* **dom:** export create class name ([#1348](https://github.com/algolia/react-instantsearch/issues/1348)) ([9017468](https://github.com/algolia/react-instantsearch/commit/9017468)) - - - - -# [5.2.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.0...v5.2.0-beta.1) (2018-06-04) - - -### Bug Fixes - -* **dom:** publish server file ([#1305](https://github.com/algolia/react-instantsearch/issues/1305)) ([bd79693](https://github.com/algolia/react-instantsearch/commit/bd79693)) - - - - -# [5.2.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.1.0...v5.2.0-beta.0) (2018-06-04) - - -This new version introduce a complete revamp of the package structure, but it should be completely transparent for the users. - -If you have any troubles with this version please open a issue on [Github](https://github.com/algolia/react-instantsearch/issues/new), thanks! - - - - -# [5.1.0](https://github.com/algolia/react-instantsearch/compare/v5.0.3...v5.1.0) (2018-05-28) - - -### Bug Fixes - -* **connectInfiniteHits:** always set a value for previous page ([#1195](https://github.com/algolia/react-instantsearch/issues/1195)) ([4c218d5](https://github.com/algolia/react-instantsearch/commit/4c218d5)) -* **indexUtils:** avoid throw an error on cleanUp multi indices ([#1265](https://github.com/algolia/react-instantsearch/issues/1265)) ([12f5ace](https://github.com/algolia/react-instantsearch/commit/12f5ace)) - - -### Features - -* **searchClient:** Add support for custom Search Clients ([#1216](https://github.com/algolia/react-instantsearch/issues/1216)) ([174cc28](https://github.com/algolia/react-instantsearch/commit/174cc28)) - - - - -## [5.0.3](https://github.com/algolia/react-instantsearch/compare/v5.0.2...v5.0.3) (2018-04-03) - - -### Bug Fixes - -* revert dependencies as devDependencies ([#1135](https://github.com/algolia/react-instantsearch/issues/1135)) ([6b627bb](https://github.com/algolia/react-instantsearch/commit/6b627bb)) - - - - -## [5.0.2](https://github.com/algolia/react-instantsearch/compare/v5.0.1...v5.0.2) (2018-04-03) - - -### Bug Fixes - -* use lodash version of unsupported Array.{fill, find} ([#1118](https://github.com/algolia/react-instantsearch/issues/1118)) ([ea7bf42](https://github.com/algolia/react-instantsearch/commit/ea7bf42)) - - - - -## [5.0.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0...v5.0.1) (2018-03-12) - - -### Bug Fixes - -* **connectInfiniteHits:** always provide an array for hits ([#1064](https://github.com/algolia/react-instantsearch/issues/1064)) ([c75e38b](https://github.com/algolia/react-instantsearch/commit/c75e38b)) - - - - -# [5.0.0](https://github.com/algolia/react-instantsearch/compare/v4.5.2...v5.0.0) (2018-03-06) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.5.2](https://github.com/algolia/react-instantsearch/compare/v4.5.1...v4.5.2) (2018-03-06) - - -### Bug Fixes - -* **connectRange:** update default refinement propTypes ([#978](https://github.com/algolia/react-instantsearch/issues/978)) ([c065fb1](https://github.com/algolia/react-instantsearch/commit/c065fb1)) -* **IndexUtils:** avoid throw an error when cleanUp multi index ([#1019](https://github.com/algolia/react-instantsearch/issues/1019)) ([865a3c3](https://github.com/algolia/react-instantsearch/commit/865a3c3)) -* **SearchBox:** avoid to bind click on reset button ([#979](https://github.com/algolia/react-instantsearch/issues/979)) ([ea3063a](https://github.com/algolia/react-instantsearch/commit/ea3063a)) - - - - -# [5.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2018-02-06) - - -Apply features & bug fixes from [v4.5.0](#450-2018-02-06) & [v4.5.1](#451-2018-02-06) on the v5. - -See their CHANGELOG for more details. - - - - -## [4.5.1](https://github.com/algolia/react-instantsearch/compare/v4.5.0...v4.5.1) (2018-02-06) - - -### Bug Fixes - -* **StarRating:** move to 1 based instead of 0 ([#949](https://github.com/algolia/react-instantsearch/issues/949)) ([eb0152d](https://github.com/algolia/react-instantsearch/commit/eb0152d)) - - - - -# [4.5.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v4.5.0) (2018-02-06) - - -### Bug Fixes - -* **connectRange:** use the same behaviour for currentRefinement in getMetadata ([#923](https://github.com/algolia/react-instantsearch/issues/923)) ([08917b6](https://github.com/algolia/react-instantsearch/commit/08917b6)) -* **connectToggle:** use currentRefinement in metadata instead of the label ([#909](https://github.com/algolia/react-instantsearch/issues/909)) ([89cae2b](https://github.com/algolia/react-instantsearch/commit/89cae2b)) -* **StarRatings:** always show the stars below ([#929](https://github.com/algolia/react-instantsearch/issues/929)) ([22bf93a](https://github.com/algolia/react-instantsearch/commit/22bf93a)) - - -### Features - -* **connectStateResults:** expose isSearchStalled ([#933](https://github.com/algolia/react-instantsearch/issues/933)) ([f45ba27](https://github.com/algolia/react-instantsearch/commit/f45ba27)) - - - -# [5.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v5.0.0-beta.0) (2018-01-30) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.4.2](https://github.com/algolia/react-instantsearch/compare/v4.4.1...v4.4.2) (2018-01-24) - - -### Bug Fixes - -* **currentRefinements:** give access to id and index from transformItems for deduplication ([#830](https://github.com/algolia/react-instantsearch/issues/830)) ([316b8f5](https://github.com/algolia/react-instantsearch/commit/316b8f5)) -* pass maxFacetHits to SFFV ([#863](https://github.com/algolia/react-instantsearch/issues/863)) ([de23a46](https://github.com/algolia/react-instantsearch/commit/de23a46)) - - - - -## [4.4.1](https://github.com/algolia/react-instantsearch/compare/v4.4.0...v4.4.1) (2018-01-09) - - -### Bug Fixes - -* **SearchBox**: clear SearchBox without search as you type ([#802](https://github.com/algolia/react-instantsearch/issues/802)) ([c49b2b6](https://github.com/algolia/react-instantsearch/commit/c49b2b6)) -* **connectRange:** check if facet exist before access ([#797](https://github.com/algolia/react-instantsearch/issues/797)) ([6520760](https://github.com/algolia/react-instantsearch/commit/6520760)) -* **stories:** avoid to use linear-background it breaks Argos every time ([#804](https://github.com/algolia/react-instantsearch/issues/804)) ([0beded7](https://github.com/algolia/react-instantsearch/commit/0beded7)) -* **stories:** limit hits per page on Index ([#806](https://github.com/algolia/react-instantsearch/issues/806)) ([6eb14d3](https://github.com/algolia/react-instantsearch/commit/6eb14d3)) - - -### Features - -* **Index:** allow custom root ([#792](https://github.com/algolia/react-instantsearch/issues/792)) ([d793b0a](https://github.com/algolia/react-instantsearch/commit/d793b0a)) - - - - -# [4.4.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0...v4.4.0) (2018-01-03) - - -### Bug Fixes - -* **createInstantSearch:** remove the client from the Snapshot ([#749](https://github.com/algolia/react-instantsearch/issues/749)) ([700d8f4](https://github.com/algolia/react-instantsearch/commit/700d8f4)) -* refresh cache memory leak example ([#784](https://github.com/algolia/react-instantsearch/issues/784)) ([cf228ac](https://github.com/algolia/react-instantsearch/commit/cf228ac)) -* **stories:** rename InstantSearch to `` ([#789](https://github.com/algolia/react-instantsearch/issues/789)) ([05efda5](https://github.com/algolia/react-instantsearch/commit/05efda5)) - - -### Features - -* InstantSearch root props ([#770](https://github.com/algolia/react-instantsearch/issues/770)) ([2d458f8](https://github.com/algolia/react-instantsearch/commit/2d458f8)) - - - - -# [4.3.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0-beta.0...v4.3.0) (2017-12-20) - - -### Bug Fixes - -* reset page with multi index ([#665](https://github.com/algolia/react-instantsearch/issues/665)) ([865b7dc](https://github.com/algolia/react-instantsearch/commit/865b7dc)) -* track all index in the manager ([#660](https://github.com/algolia/react-instantsearch/issues/660)) ([793502b](https://github.com/algolia/react-instantsearch/commit/793502b)) - - -### Features - -* **SearchBox:** provide a loading indicator ([#544](https://github.com/algolia/react-instantsearch/issues/544)) ([189659e](https://github.com/algolia/react-instantsearch/commit/189659e)) -* **Highlight:** support array of strings ([#715](https://github.com/algolia/react-instantsearch/issues/715)) ([8e93c6a](https://github.com/algolia/react-instantsearch/commit/8e93c6a)) - - - - -# [4.3.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.2.0...v4.3.0-beta.0) (2017-11-27) - - -### Bug Fixes - -* **babelrc:** add a key for each env development, production, es ([#547](https://github.com/algolia/react-instantsearch/issues/547)) ([fa9528d](https://github.com/algolia/react-instantsearch/commit/fa9528d)) -* **localizecount:** allow localized string for count in MenuSelect ([#657](https://github.com/algolia/react-instantsearch/issues/657)) ([67ebd34](https://github.com/algolia/react-instantsearch/commit/67ebd34)) -* **react-router-example:** Properly update search query when using browser navigation ([#604](https://github.com/algolia/react-instantsearch/issues/604)) ([9ee6600](https://github.com/algolia/react-instantsearch/commit/9ee6600)) - - -### Features - -* **refreshcache:** add prop refresh to InstantSearch instance ([#619](https://github.com/algolia/react-instantsearch/issues/619)) ([19f6de0](https://github.com/algolia/react-instantsearch/commit/19f6de0)) - - - - -# [4.2.0](https://github.com/algolia/react-instantsearch/compare/v4.1.3...v4.2.0) (2017-11-02) - - -### Bug Fixes - -* **connectRange:** handle boundaries on first call ([9f14dc0](https://github.com/algolia/react-instantsearch/commit/9f14dc0)) -* **connectRange:** use refine instead of cleanUp in metadata ([#526](https://github.com/algolia/react-instantsearch/issues/526)) ([1861235](https://github.com/algolia/react-instantsearch/commit/1861235)) -* **hierarchicaMenu:** allow sorting and using limit ([fe178ed](https://github.com/algolia/react-instantsearch/commit/fe178ed)), closes [#92](https://github.com/algolia/react-instantsearch/issues/92) -* **InfiniteHits:** add disabled style to the LoadMore button ([#477](https://github.com/algolia/react-instantsearch/issues/477)) ([faba1ad](https://github.com/algolia/react-instantsearch/commit/faba1ad)) -* **Range:** handle float, allow reset and respect boundaries ([75969b8](https://github.com/algolia/react-instantsearch/commit/75969b8)) -* **RangeInput:** fix compatibility with React 16 & Panel ([3f218db](https://github.com/algolia/react-instantsearch/commit/3f218db)) -* **searchbox:** add maxlength 512 ([#542](https://github.com/algolia/react-instantsearch/issues/542)) ([5bd4033](https://github.com/algolia/react-instantsearch/commit/5bd4033)), closes [#510](https://github.com/algolia/react-instantsearch/issues/510) - - -### Features - -* **MenuSelect:** add component and connector ([cc6e0d7](https://github.com/algolia/react-instantsearch/commit/cc6e0d7)) - - - - -## [4.1.3](https://github.com/algolia/react-instantsearch/compare/v4.1.2...v4.1.3) (2017-10-09) - - -### Bug Fixes - -* **List:** remove React16 warning ([#442](https://github.com/algolia/react-instantsearch/issues/442)) ([8d6cf18](https://github.com/algolia/react-instantsearch/commit/8d6cf18)) - - -### Features - -* **connectStateResults:** add component props ([#434](https://github.com/algolia/react-instantsearch/issues/434)) ([c629b97](https://github.com/algolia/react-instantsearch/commit/c629b97)) - - - - -## [4.1.2](https://github.com/algolia/react-instantsearch/compare/v4.1.1...v4.1.2) (2017-09-26) - - -### Features - -* **Conditional:** add connectStateResults connector ([#357](https://github.com/algolia/react-instantsearch/issues/357)) ([462df5f](https://github.com/algolia/react-instantsearch/commit/462df5f)) - - - - -## [4.1.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0...v4.1.1) (2017-09-13) - - -### Bug Fixes - -* **MultiIndex:** reset page to 1 when share widgets refine (#312) ([c85a7bf](https://github.com/algolia/react-instantsearch/commit/c85a7bf)) -* **MultiIndex:** Trigger new search when `` props are updated (#318) ([bb11965](https://github.com/algolia/react-instantsearch/commit/bb11965)) - - - - -# [4.1.0](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.5...v4.1.0) (2017-08-28) - - -### Bug Fixes - -* **Highlighting:** revert breaking change (#245) ([045ee06](https://github.com/algolia/react-instantsearch/commit/045ee06)) -* **List:** adds support for any type of renderable element (#266) ([d848bb6](https://github.com/algolia/react-instantsearch/commit/d848bb6)) -* **Pagination:** fixed the offset ([3c0fff2](https://github.com/algolia/react-instantsearch/commit/3c0fff2)) -* **PoweredBy:** aria-* tags are not camelcased (#261) ([dc4a5bb](https://github.com/algolia/react-instantsearch/commit/dc4a5bb)) - - - - -# [4.1.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2017-08-08) - - -### Bug Fixes - -* **SSR:** clean SP before rendering agan (#238) ([e765886](https://github.com/algolia/react-instantsearch/commit/e765886)) - - -### Features - -* **Breadcrumb:** add a new widget & connector (#228) ([7f8f3ae](https://github.com/algolia/react-instantsearch/commit/7f8f3ae)) - - - - -# [4.1.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2017-08-03) - - -### Bug Fixes - -* **deps:** Update dependency lint-staged to version ^4.0.0 (#201) ([6867a1b](https://github.com/algolia/react-instantsearch/commit/6867a1b)) -* **nextjs/ssr:** parse `params.asPath` (#189) ([ae17da0](https://github.com/algolia/react-instantsearch/commit/ae17da0)) -* **PoweredBy:** add a label to the Algolia logo (#216) ([cd235bd](https://github.com/algolia/react-instantsearch/commit/cd235bd)) -* **react:** remove typo around `"" 2` (#220) ([f73eb04](https://github.com/algolia/react-instantsearch/commit/f73eb04)) -* **ScrollTo:** scroll to only if change triggered by the widget observed (#202) ([2d76022](https://github.com/algolia/react-instantsearch/commit/2d76022)) -* **theme:** format the count of items appearing in a refinement (#217) ([2225c24](https://github.com/algolia/react-instantsearch/commit/2225c24)) - - - - -# [4.1.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2017-07-25) - - -### Bug Fixes - -* **error:** reset error when receiving results of a query (not when sending it) (#179) ([bb12c29](https://github.com/algolia/react-instantsearch/commit/bb12c29)) -* **highlight:** wrong parsing between client and server (#183) ([2daae70](https://github.com/algolia/react-instantsearch/commit/2daae70)) -* **poweredBy:** SSR compatibility (#181) ([ec0fa8a](https://github.com/algolia/react-instantsearch/commit/ec0fa8a)) - - -### BREAKING CHANGES - -* **highlight:** We remove the timestamp present in our highlight preTag and postTag. If you were using regex to parse the -highlighting results then you'll need to adapt it as now it's only "ais-highlight". - - - - -# [4.1.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2017-07-20) - - -### Bug Fixes - -* **error:** reset error if next query is successful (#175) ([ff50a07](https://github.com/algolia/react-instantsearch/commit/ff50a07)) - - - - -# [4.1.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2017-07-12) - - - - -# [4.1.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.0.7...v4.1.0-beta.0) (2017-07-10) - - -### Bug Fixes - -* **argos:** address flakyness (#152) ([84ef8f1](https://github.com/algolia/react-instantsearch/commit/84ef8f1)) - - -### Features - -* **server-side rendering:** Add API features for server-side rendering ([86b14d1](https://github.com/algolia/react-instantsearch/commit/86b14d1)) - - - - -## [4.0.7](https://github.com/algolia/react-instantsearch/compare/v4.0.6...v4.0.7) (2017-07-06) - - -### Bug Fixes - -* **results:** revert commit that ensure hits are returned only if right indices (#149) ([df9aa25](https://github.com/algolia/react-instantsearch/commit/df9aa25)) - - - - -## [4.0.6](https://github.com/algolia/react-instantsearch/compare/v4.0.5...v4.0.6) (2017-06-29) - - -### Bug Fixes - -* **store:** delay call to listener to prevent infinite loops (#143) ([0945958](https://github.com/algolia/react-instantsearch/commit/0945958)) - - - - -## [4.0.5](https://github.com/algolia/react-instantsearch/compare/v4.0.4...v4.0.5) (2017-06-26) - - -### Bug Fixes - -* **MultiIndex:** ensure getResults return only hits matching index in the context (#136) ([124ffe6](https://github.com/algolia/react-instantsearch/commit/124ffe6)) -* **MultiIndex:** handle if namespace isn't in search state (#139) ([1aab324](https://github.com/algolia/react-instantsearch/commit/1aab324)) -* **storybook:** process CSS through autoprefixer (#138) ([62cf512](https://github.com/algolia/react-instantsearch/commit/62cf512)) - - - - -## [4.0.4](https://github.com/algolia/react-instantsearch/compare/v4.0.3...v4.0.4) (2017-06-19) - - -### Bug Fixes - -* **MultiIndex:** handle switch between mono and multi index (#132) ([e161921](https://github.com/algolia/react-instantsearch/commit/e161921)) - - - - -## [4.0.3](https://github.com/algolia/react-instantsearch/compare/v4.0.2...v4.0.3) (2017-06-14) - - -### Bug Fixes - -* **SFFV:** search status we're not inside search state (#125) ([5f3e670](https://github.com/algolia/react-instantsearch/commit/5f3e670)) - - - - -## [4.0.2](https://github.com/algolia/react-instantsearch/compare/v4.0.1...v4.0.2) (2017-05-30) - - - - -## [4.0.1](https://github.com/algolia/react-instantsearch/compare/v4.0.0...v4.0.1) (2017-05-17) - - -### Bug Fixes - -* **state:** nested attributes for faceting were not handled ([11bd122](https://github.com/algolia/react-instantsearch/commit/11bd122)) - - - - -# [4.0.0](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.6...v4.0.0) (2017-05-15) - -### Features and migration guide - -You can find all the details of the release and the migration guide from v3 to v4 here: https://discourse.algolia.com/t/react-instantsearch-v4/1329. - - - -# [4.0.0-beta.6](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2017-05-04) - - - - -# [4.0.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2017-05-02) - - -### Bug Fixes - -* **connectAutoComplete:** allow usage with hits from a single index (#75) ([8b3b358](https://github.com/algolia/react-instantsearch/commit/8b3b358)), closes [#74](https://github.com/algolia/react-instantsearch/issues/74) -* **InstantSearch:** update algoliaClient when it change (#70) ([9e97dbd](https://github.com/algolia/react-instantsearch/commit/9e97dbd)) - - - - -# [4.0.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2017-04-25) - - -### Bug Fixes - -* **MultIndex:** no need to nest hits, if those are from main index. (#56) ([86e0bd7](https://github.com/algolia/react-instantsearch/commit/86e0bd7)) - - -### Features - -* **MultiIndex:** remove the need for virtual hits when using connectAutoComplete (#45) ([7549019](https://github.com/algolia/react-instantsearch/commit/7549019)) - - - - -# [4.0.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2017-04-21) - - -### Bug Fixes - -* replace usage of Object.values (#47) ([4c79e3e](https://github.com/algolia/react-instantsearch/commit/4c79e3e)) - - - - -# [4.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2017-04-18) - - -### Bug Fixes - -* **InstantSearch:** dont fire request/onsearchStateChange when unmounting (#26) ([9a1487a](https://github.com/algolia/react-instantsearch/commit/9a1487a)) -* **MultiIndex:** derived helper were using main index specifics params (#36) ([991fea6](https://github.com/algolia/react-instantsearch/commit/991fea6)) -* **MultiIndex:** revert breaking change if no multiple index (#32) ([44f7de0](https://github.com/algolia/react-instantsearch/commit/44f7de0)) -* **util:** remove empty key was removing non object key (#29) ([9f795c7](https://github.com/algolia/react-instantsearch/commit/9f795c7)) - - -### Features - -* **Highlighter:** allow rendering to custom tag (#11) ([52a1212](https://github.com/algolia/react-instantsearch/commit/52a1212)) -* **SearchBox:** add default width and height to buttons. (#34) ([bcabf9b](https://github.com/algolia/react-instantsearch/commit/bcabf9b)) - - - - -# [4.0.0-beta.1](https://github.com/algolia/instantsearch.js/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2017-04-03) - - -### Bug Fixes - -* **SFFV:** fix wrong query behaviour with slow network (#2086) ([c251e8f](https://github.com/algolia/instantsearch.js/commit/c251e8f)), closes [#2086](https://github.com/algolia/instantsearch.js/issues/2086) - - - - -# [4.0.0-beta.0](https://github.com/algolia/instantsearch.js/compare/v3.3.0...v4.0.0-beta.0) (2017-03-28) - - -### Features - -* **multi-index:** ease multi index and auto complete ([09a4e1d](https://github.com/algolia/instantsearch.js/commit/09a4e1d)) - - -### BREAKING CHANGES - -* multi-index: * Reseting the pagination should be done at each connector level inside the "refine" function when returning the search state. -* The current page now appears inside the search state when a widget is used -* Query values are part of the items prop of the connectCurrentRefinements connector. Behaviour is unchanged, query will be filtered if clearsQuery prop is false. -* Add the index name to all the current refinements items. (not used by our widgets yet, but available if needed). - - - - -# [3.3.0](https://github.com/algolia/instantsearch.js/compare/v3.2.2-beta0...v3.3.0) (2017-03-22) - - -### Bug Fixes - -* **example:** Fix access to props in react-router example ([1417d6f](https://github.com/algolia/instantsearch.js/commit/1417d6f)) - - - - -## [3.2.2-beta0](https://github.com/algolia/instantsearch.js/compare/v3.2.1...v3.2.2-beta0) (2017-03-20) - - -### Bug Fixes - -* **InfiniteHits:** provide translation key for `Load More` (#2048) ([6130bf2](https://github.com/algolia/instantsearch.js/commit/6130bf2)) -* **SearchBox:** better mobile behaviour by default ([ea968b3](https://github.com/algolia/instantsearch.js/commit/ea968b3)) -* **example:** link to instantsearch/react (#2007) ([5e674cd](https://github.com/algolia/instantsearch.js/commit/5e674cd)) -* **recipes:** react router v4 ([de673bf](https://github.com/algolia/instantsearch.js/commit/de673bf)) - - -### Features - -* **SearchBox:** add role=search to the form (#2046) ([d1e90f3](https://github.com/algolia/instantsearch.js/commit/d1e90f3)) -* **SearchBox:** allow custom reset and submit components (#1991) ([cd303d7](https://github.com/algolia/instantsearch.js/commit/cd303d7)) -* **searchBox:** add event handling ([e267ab6](https://github.com/algolia/instantsearch.js/commit/e267ab6)), closes [#2017](https://github.com/algolia/instantsearch.js/issues/2017) - - - - -## [3.2.1](https://github.com/algolia/instantsearch.js/compare/v3.2.0...v3.2.1) (2017-02-22) - - -### Bug Fixes - -* **umd:** Add connectors to UMD build (#1988) ([23ac5e6](https://github.com/algolia/instantsearch.js/commit/23ac5e6)), closes [#1987](https://github.com/algolia/instantsearch.js/issues/1987) - - - - -# [3.2.0](https://github.com/algolia/instantsearch.js/compare/v3.1.0...v3.2.0) (2017-02-15) - - -### Bug Fixes - -* **Configure:** use props a unique source of truth (#1967) ([9d53d86](https://github.com/algolia/instantsearch.js/commit/9d53d86)) -* **SearchBox:** Safari can only have with xlinkHref (#1970) ([7ab00bd](https://github.com/algolia/instantsearch.js/commit/7ab00bd)), closes [#1968](https://github.com/algolia/instantsearch.js/issues/1968) - - -### Features - -* **MultiRange:** add an all range (#1959) ([a3dc950](https://github.com/algolia/instantsearch.js/commit/a3dc950)) - - -### BREAKING CHANGES - -* MultiRange: - MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system. - - - - -# [3.1.0](https://github.com/algolia/instantsearch.js/compare/v3.0.0...v3.1.0) (2017-02-08) - - -### Bug Fixes - -* **Configure:** call onSearchStateChange when props are updated (#1953) ([7e151db](https://github.com/algolia/instantsearch.js/commit/7e151db)), closes [#1950](https://github.com/algolia/instantsearch.js/issues/1950) -* **Configure:** trigger onSearchStateChange with the right data ([11e5af8](https://github.com/algolia/instantsearch.js/commit/11e5af8)) -* **createConnector:** updates with latest props on state change (#1951) ([cd3a82c](https://github.com/algolia/instantsearch.js/commit/cd3a82c)) - - -### Features - -* **ClearAll:** add withQuery to also clear the search query (#1958) ([c0e695b](https://github.com/algolia/instantsearch.js/commit/c0e695b)) - - - - -# [3.0.0](https://github.com/algolia/instantsearch.js/compare/v2.2.5...v3.0.0) (2017-02-06) - - -### Bug Fixes - -* ***List:** disable shortcuts in *List SearchBoxes (#1921) ([51a76ae](https://github.com/algolia/instantsearch.js/commit/51a76ae)), closes [#1920](https://github.com/algolia/instantsearch.js/issues/1920) -* **Configure:** add configure parameters in search state (#1935) ([0971330](https://github.com/algolia/instantsearch.js/commit/0971330)), closes [#1863](https://github.com/algolia/instantsearch.js/issues/1863) -* **Hits:** limit the hitComponent to be only a function (#1912) ([b3c9578](https://github.com/algolia/instantsearch.js/commit/b3c9578)) -* **Pagination:** fix and indicate when pagination is disabled ([5f20199](https://github.com/algolia/instantsearch.js/commit/5f20199)), closes [#1938](https://github.com/algolia/instantsearch.js/issues/1938) -* **StarRating:** usage with filters (#1933) ([667e9d5](https://github.com/algolia/instantsearch.js/commit/667e9d5)) -* **withSearchBox:** keep displaying searchBox when no items found (#1930) ([30de4cd](https://github.com/algolia/instantsearch.js/commit/30de4cd)) - - -### Features - -* **MultiRange:** indicate if a range has no refinements (#1926) ([80b6450](https://github.com/algolia/instantsearch.js/commit/80b6450)) -* **panel:** add a panel widget (#1889) ([594e1a1](https://github.com/algolia/instantsearch.js/commit/594e1a1)) -* **starRating:** indicate when any refinement has no effect ([c547ae5](https://github.com/algolia/instantsearch.js/commit/c547ae5)) -* **widgets:** default design for disabled states (#1929) ([31f010b](https://github.com/algolia/instantsearch.js/commit/31f010b)) - -### Migration guide - -The migration to V3.0.0 should be safe and you should do it. - -There are two breaking changes that you will need to handle in your codebase: -- Anytime you are using a connector, when there are no more items in it or no more hits, we will still call your Component. Thus you will have to handle cases like dealing with empty arrays and decide if you want to unmount or hide the widget. -- Anytime you are using a widget, when there are no more items in it or no more hits, we will still display the widget. You can then decide to hide it with CSS. - - -## [2.2.5](https://github.com/algolia/instantsearch.js/compare/v2.2.4...v2.2.5) (2017-01-23) - - -### Bug Fixes - -* **currentRefinements:** make removing a toggle refinement work ([8995e64](https://github.com/algolia/instantsearch.js/commit/8995e64)) - - - - -## [2.2.4](https://github.com/algolia/instantsearch.js/compare/v2.2.3...v2.2.4) (2017-01-20) - - -### Bug Fixes - -* **publish:** publish react-instantsearch/dist instead of root (#1884) ([64414e0](https://github.com/algolia/instantsearch.js/commit/64414e0)) - - - - -## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-01-20) - - -### Bug Fixes - -* **SFFV:** translations for searchbox were not applied (#1879) ([e9b4ee1](https://github.com/algolia/instantsearch.js/commit/e9b4ee1)) - - - - -## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-01-18) - - -### Bug Fixes - -* **react-router:** search was triggered two many times (#1840) ([25e9db5](https://github.com/algolia/instantsearch.js/commit/25e9db5)) -* **SFFV:** empty query triggered a new SFFV (#1875) ([6c8259a](https://github.com/algolia/instantsearch.js/commit/6c8259a)) - - - - -## [2.2.1](https://github.com/algolia/instantsearch.js/compare/v2.2.0...v2.2.1) (2017-01-18) - - -### Bug Fixes - -* **createInstantsearch:** fix missing props (#1867) ([8d319b5](https://github.com/algolia/instantsearch.js/commit/8d319b5)), closes [#1867](https://github.com/algolia/instantsearch.js/issues/1867) - - - - -# [2.2.0](https://github.com/algolia/instantsearch.js/compare/v2.1.0...v2.2.0) (2017-01-17) - - -### Bug Fixes - -* **clear:** clearing wasn't working with too+ same type facets selected (#1820) ([a9a2364](https://github.com/algolia/instantsearch.js/commit/a9a2364)) -* **connectSearchBox:** handle `defaultRefinement` (#1829) ([7a730e2](https://github.com/algolia/instantsearch.js/commit/7a730e2)), closes [#1826](https://github.com/algolia/instantsearch.js/issues/1826) -* **Instantsearch:** Update all props on InstantSearch (#1828) ([2ed9b49](https://github.com/algolia/instantsearch.js/commit/2ed9b49)) -* **InstantSearch:** add specific `react-instantsearch ${version}` agent (#1844) ([a1113bc](https://github.com/algolia/instantsearch.js/commit/a1113bc)) -* **SFFV:** correct propTypes and add missing default values (#1845) ([a4c1b31](https://github.com/algolia/instantsearch.js/commit/a4c1b31)) -* **test:** add missing Snippet and Highliter snapshot ([4accce5](https://github.com/algolia/instantsearch.js/commit/4accce5)) -* **widgets:** replace setImmediate use with Promise use when update is needed (#1811) ([17e2497](https://github.com/algolia/instantsearch.js/commit/17e2497)) - - -### Features - -* **Menu, connectMenu:** add search for facet values (#1822) ([a6c513e](https://github.com/algolia/instantsearch.js/commit/a6c513e)) -* **snippet:** add a snippet widget to be able to highlight snippet results (#1797) ([2aecc40](https://github.com/algolia/instantsearch.js/commit/2aecc40)) -* **widgets:** add transformItems to be able to sort and filter (#1809) ([ba539f0](https://github.com/algolia/instantsearch.js/commit/ba539f0)) - - - - -# [2.1.0](https://github.com/algolia/instantsearch.js/compare/v2.0.1...v2.1.0) (2017-01-04) - - -### Bug Fixes - -* **createInstantSearchManager:** drop outdated response (#1765) ([76c5312](https://github.com/algolia/instantsearch.js/commit/76c5312)) -* **highlight:** highlight should work even if the attribute is missing (#1791) ([5b79b15](https://github.com/algolia/instantsearch.js/commit/5b79b15)), closes [#1790](https://github.com/algolia/instantsearch.js/issues/1790) -* **InfiniteHits:** better classname to loadmore btn (#1789) ([ad2ded3](https://github.com/algolia/instantsearch.js/commit/ad2ded3)) -* **starRatings:** click on selected range doesn't unselect it (#1766) ([beacc72](https://github.com/algolia/instantsearch.js/commit/beacc72)) -* **website:** broken demo links (#1802) ([0abe2f5](https://github.com/algolia/instantsearch.js/commit/0abe2f5)) -* **widgets:** add 300px width for the default SearchBox (#1803) ([bf5d791](https://github.com/algolia/instantsearch.js/commit/bf5d791)) - - -### Features - -* **InfiniteHits:** Add class to load more button (#1787) ([416febd](https://github.com/algolia/instantsearch.js/commit/416febd)) -* **RefinementList, connectRefinementList:** allow to search for facet values ([e086a81](https://github.com/algolia/instantsearch.js/commit/e086a81)) - - - - -## [2.0.1](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.1) (2016-12-15) - - -### Bug Fixes - -* **connectRange:** when unfinite numbers are passed throw ([75bec0d](https://github.com/algolia/instantsearch.js/commit/75bec0d)) -* **react-native:** use View as a container for react-native (#1729) ([5b76f75](https://github.com/algolia/instantsearch.js/commit/5b76f75)), closes [#1730](https://github.com/algolia/instantsearch.js/issues/1730) -* **SearchBox:** autocomplete was not disabled by default (#1742) ([bc76618](https://github.com/algolia/instantsearch.js/commit/bc76618)) -* **starRating:** call createURL with the right interface (min/max) (#1747) ([f9ab9b6](https://github.com/algolia/instantsearch.js/commit/f9ab9b6)) - - - - -## [2.0.0](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.0) (2016-12-08) - -First release of `react-instantsearch` diff --git a/packages/react-instantsearch-hooks/README.md b/packages/react-instantsearch-hooks/README.md deleted file mode 100644 index b962037f90..0000000000 --- a/packages/react-instantsearch-hooks/README.md +++ /dev/null @@ -1,81 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [react-instantsearch-hooks](#react-instantsearch-hooks) - - [Installation](#installation) - - [Getting started](#getting-started) - - [API reference](#api-reference) - - [Documentation](#documentation) - - [Contributing](#contributing) - - [License](#license) - - - -# react-instantsearch-hooks - -React InstantSearch Hooks is an open-source UI library for React that lets you quickly build a search interface in your front-end application. - -InstantSearch’s goal is to help you implement awesome search experiences as smoothly as possible by providing a [complete search ecosystem](https://algolia.com/doc/guides/getting-started/how-algolia-works/#the-full-ecosystem). InstantSearch tackles an important part of this vast goal by providing front-end primitives that you can assemble into unique search interfaces. - -

    - - Edit on CodeSandbox - -

    - -> Note: `react-instantsearch-hooks` exports renderless components and hooks which can be used for both web and React Native. If you are using React in a web project, we recommend using the package `react-instantsearch-hooks-web` instead, as it includes complete components that render to the DOM. - -## Installation - -React InstantSearch Hooks is available on the npm registry. It relies on [`algoliasearch`](https://github.com/algolia/algoliasearch-client-javascript) to communicate with Algolia APIs. - -```sh -yarn add algoliasearch react-instantsearch-hooks -# or -npm install algoliasearch react-instantsearch-hooks -``` - -## Getting started - -React InstantSearch Hooks is a headless React library that lets you create an instant search results experience using Algolia’s search API. - -Check out our [**Getting Started guide**](https://algolia.com/doc/guides/building-search-ui/getting-started/react-hooks/) to start implementing a full-featured search experience with React InstantSearch Hooks. - -## API reference - -Check out the [**API reference**](https://www.algolia.com/doc/api-reference/widgets/react-hooks/). - -## Documentation - -The documentation is available on [algolia.com/doc](https://algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/). - -## Contributing - -We welcome all contributors, from casual to regular 💙 - -- **Bug report**. Is something not working as expected? [Send a bug report][contributing-bugreport]. -- **Feature request**. Would you like to add something to the library? [Send a feature request][contributing-featurerequest]. -- **Documentation**. Did you find a typo in the doc? [Open an issue][contributing-newissue] and we'll take care of it. -- **Development**. If you don't know where to start, you can check the open issues that are [tagged easy][contributing-label-easy], the [bugs][contributing-label-bug] or [chores][contributing-label-chore]. - -To start contributing to code, you need to: - -1. [Fork the project](https://help.github.com/articles/fork-a-repo/) -1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) -1. Install the dependencies: `yarn` - -Please read [our contribution process](https://github.com/algolia/instantsearch.js/blob/master/CONTRIBUTING.md) to learn more. - -## License - -React InstantSearch Hooks is [MIT licensed](../../LICENSE). - - - -[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch+Hooks&title=Feature%20request%3A%20 -[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 diff --git a/packages/react-instantsearch-hooks/global.d.ts b/packages/react-instantsearch-hooks/global.d.ts deleted file mode 100644 index b867229b43..0000000000 --- a/packages/react-instantsearch-hooks/global.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare const __DEV__: boolean; diff --git a/packages/react-instantsearch-hooks/package.json b/packages/react-instantsearch-hooks/package.json deleted file mode 100644 index ce75facbd5..0000000000 --- a/packages/react-instantsearch-hooks/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "react-instantsearch-hooks", - "version": "6.47.3", - "description": "⚡ Lightning-fast search for React, by Algolia", - "source": "src/index.ts", - "types": "dist/es/index.d.ts", - "main": "dist/cjs/index.js", - "module": "dist/es/index.js", - "type": "module", - "exports": { - ".": { - "import": "./dist/es/index.js", - "require": "./dist/cjs/index.js" - } - }, - "sideEffects": false, - "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/", - "repository": { - "type": "git", - "url": "https://github.com/algolia/instantsearch.js" - }, - "author": { - "name": "Algolia, Inc.", - "url": "https://www.algolia.com" - }, - "keywords": [ - "algolia", - "components", - "fast", - "instantsearch", - "react", - "search" - ], - "files": [ - "README.md", - "dist" - ], - "scripts": { - "clean": "rm -rf dist", - "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es && yarn build:umd && yarn build:types", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet && ../../scripts/prepare-cjs.sh", - "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:umd": "BABEL_ENV=rollup rollup -c rollup.config.js", - "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", - "test:exports": "node ./test/module/is-es-module.mjs && node ./test/module/is-cjs-module.cjs", - "version": "./scripts/version.cjs" - }, - "dependencies": { - "@babel/runtime": "^7.1.2", - "algoliasearch-helper": "3.14.0", - "instantsearch.js": "4.56.8", - "use-sync-external-store": "^1.0.0" - }, - "devDependencies": { - "@types/use-sync-external-store": "0.0.3" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.8.0 < 19" - } -} diff --git a/packages/react-instantsearch-hooks/rollup.config.js b/packages/react-instantsearch-hooks/rollup.config.js deleted file mode 100644 index 0f2347d61a..0000000000 --- a/packages/react-instantsearch-hooks/rollup.config.js +++ /dev/null @@ -1,80 +0,0 @@ -import babel from 'rollup-plugin-babel'; -import commonjs from 'rollup-plugin-commonjs'; -import filesize from 'rollup-plugin-filesize'; -import globals from 'rollup-plugin-node-globals'; -import resolve from 'rollup-plugin-node-resolve'; -import replace from 'rollup-plugin-replace'; -import { uglify } from 'rollup-plugin-uglify'; - -const clear = (x) => x.filter(Boolean); - -const version = process.env.VERSION || 'UNRELEASED'; -const algolia = '© Algolia, inc.'; -const link = 'https://github.com/algolia/instantsearch.js'; -const createBanner = (name) => - `/*! React InstantSearch${name} ${version} | ${algolia} | ${link} */`; - -const plugins = [ - babel({ - exclude: /node_modules|algoliasearch-helper/, - extensions: ['.js', '.ts', '.tsx'], - rootMode: 'upward', - runtimeHelpers: true, - }), - resolve({ - browser: true, - preferBuiltins: false, - extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], - }), - commonjs({ - namedExports: { - '../../node_modules/use-sync-external-store/shim/index.js': [ - 'useSyncExternalStore', - ], - }, - }), - globals(), - replace({ - 'process.env.NODE_ENV': JSON.stringify('production'), - }), - filesize({ - showMinifiedSize: false, - showGzippedSize: true, - }), -]; - -const createConfiguration = ({ name, minify = false } = {}) => ({ - input: 'src/index.ts', - external: ['react'], - output: { - file: `dist/umd/ReactInstantSearch${name}${minify ? '.min' : ''}.js`, - name: `ReactInstantSearch${name}`, - format: 'umd', - globals: { - react: 'React', - }, - banner: createBanner(name), - sourcemap: true, - }, - plugins: plugins.concat( - clear([ - minify && - uglify({ - output: { - preamble: createBanner(name), - }, - }), - ]) - ), -}); - -export default [ - createConfiguration({ - name: 'Hooks', - }), - - createConfiguration({ - name: 'Hooks', - minify: true, - }), -]; diff --git a/packages/react-instantsearch-hooks/src/__tests__/index.test.ts b/packages/react-instantsearch-hooks/src/__tests__/index.test.ts deleted file mode 100644 index 74ba2f792b..0000000000 --- a/packages/react-instantsearch-hooks/src/__tests__/index.test.ts +++ /dev/null @@ -1,15 +0,0 @@ -describe('warnings', () => { - it('warns on import after release', () => { - jest.useFakeTimers('modern').setSystemTime(new Date('2023-08-09')); - - expect(() => require('../index')).toWarnDev( - '[InstantSearch] The package `react-instantsearch-hooks` is replaced by `react-instantsearch-core`. The API is the same, but the package name has changed. Please update your dependencies and follow the migration guide: https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/' - ); - }); - - it('does not warn on import before release', () => { - jest.useFakeTimers('modern').setSystemTime(new Date('2023-08-08')); - - expect(() => require('../index')).not.toWarnDev(); - }); -}); diff --git a/packages/react-instantsearch-hooks/src/index.ts b/packages/react-instantsearch-hooks/src/index.ts deleted file mode 100644 index 0eed78859d..0000000000 --- a/packages/react-instantsearch-hooks/src/index.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { warn } from './lib/warn'; - -warn( - Date.now() < new Date('2023-08-09').getTime(), - 'The package `react-instantsearch-hooks` is replaced by `react-instantsearch-core`. The API is the same, but the package name has changed. Please update your dependencies and follow the migration guide: https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/' -); - -export { default as version } from './version'; -export * from './components/Configure'; -export * from './components/DynamicWidgets'; -export * from './components/Index'; -export * from './components/InstantSearch'; -export * from './components/InstantSearchServerContext'; -export * from './components/InstantSearchSSRProvider'; -export * from './connectors/useBreadcrumb'; -export * from './connectors/useClearRefinements'; -export * from './connectors/useConfigure'; -export * from './connectors/useCurrentRefinements'; -export * from './connectors/useDynamicWidgets'; -export * from './connectors/useGeoSearch'; -export * from './connectors/useHierarchicalMenu'; -export * from './connectors/useHits'; -export * from './connectors/useHitsPerPage'; -export * from './connectors/useInfiniteHits'; -export * from './connectors/useMenu'; -export * from './connectors/useNumericMenu'; -export * from './connectors/usePagination'; -export * from './connectors/usePoweredBy'; -export * from './connectors/useQueryRules'; -export * from './connectors/useRange'; -export * from './connectors/useRefinementList'; -export * from './connectors/useSearchBox'; -export * from './connectors/useSortBy'; -export * from './connectors/useStats'; -export * from './connectors/useToggleRefinement'; -export * from './hooks/useConnector'; -export * from './hooks/useInstantSearch'; diff --git a/packages/react-instantsearch-hooks/test/module/is-cjs-module.cjs b/packages/react-instantsearch-hooks/test/module/is-cjs-module.cjs deleted file mode 100644 index f659152499..0000000000 --- a/packages/react-instantsearch-hooks/test/module/is-cjs-module.cjs +++ /dev/null @@ -1,9 +0,0 @@ -/* eslint-disable no-console */ - -const assert = require('assert'); - -const ReactInstantSearchHooks = require('react-instantsearch-hooks'); - -assert.ok(ReactInstantSearchHooks); - -console.log('react-instantsearch-hooks is valid CJS'); diff --git a/packages/react-instantsearch-hooks/test/module/is-es-module.mjs b/packages/react-instantsearch-hooks/test/module/is-es-module.mjs deleted file mode 100644 index 98a477ee7e..0000000000 --- a/packages/react-instantsearch-hooks/test/module/is-es-module.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/* eslint-disable no-console */ -import assert from 'assert'; - -import * as ReactInstantSearchHooks from 'react-instantsearch-hooks'; - -assert.ok(ReactInstantSearchHooks); - -console.log('react-instantsearch-hooks is valid ESM'); diff --git a/packages/react-instantsearch-hooks/tsconfig.declaration.json b/packages/react-instantsearch-hooks/tsconfig.declaration.json deleted file mode 100644 index 1e0c6449f8..0000000000 --- a/packages/react-instantsearch-hooks/tsconfig.declaration.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../tsconfig.declaration" -} diff --git a/packages/react-instantsearch-native/CHANGELOG.md b/packages/react-instantsearch-native/CHANGELOG.md deleted file mode 100644 index 71406a6aea..0000000000 --- a/packages/react-instantsearch-native/CHANGELOG.md +++ /dev/null @@ -1,1855 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -## [6.40.4](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.40.3...react-instantsearch-native@6.40.4) (2023-07-25) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.40.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.40.2...react-instantsearch-native@6.40.3) (2023-07-19) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.40.1...react-instantsearch-native@6.40.2) (2023-07-18) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.40.0...react-instantsearch-native@6.40.1) (2023-06-20) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.39.1...react-instantsearch-native@6.39.2) (2023-05-16) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.38.3...react-instantsearch-native@6.39.1) (2023-01-26) - -**Note:** Version bump only for package react-instantsearch-native - - - - - - -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.38.2...react-instantsearch-native@6.38.3) (2023-01-09) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-native@6.38.1...react-instantsearch-native@6.38.2) (2023-01-03) - -**Note:** Version bump only for package react-instantsearch-native - - - - - -## [6.38.1](https://github.com/algolia/react-instantsearch/compare/v6.38.0...v6.38.1) (2022-11-08) - - -### Bug Fixes - -* **hooks:** avoid effect in useStableValue ([#3670](https://github.com/algolia/react-instantsearch/issues/3670)) ([d1f53ae](https://github.com/algolia/react-instantsearch/commit/d1f53ae815b75f13c18fd245e0403d57e7ae391c)) - - - -# [6.38.0](https://github.com/algolia/react-instantsearch/compare/v6.37.0...v6.38.0) (2022-10-25) - - -### Features - -* **getServerState:** allow users to inject renderToString ([#3658](https://github.com/algolia/react-instantsearch/issues/3658)) ([9c10449](https://github.com/algolia/react-instantsearch/commit/9c104497b9b32337f288d70a2582c41cafb13cd6)), closes [#3633](https://github.com/algolia/react-instantsearch/issues/3633) [#3618](https://github.com/algolia/react-instantsearch/issues/3618) [vercel/next.js#40067](https://github.com/vercel/next.js/issues/40067) - -* **PoweredBy:** update component logo ([#3661](https://github.com/algolia/react-instantsearch/issues/3661)) ([69c1b2a](https://github.com/algolia/react-instantsearch/commit/69c1b2acef64d972dfa6c6beb8967032119ad2d5)) - - - -# [6.37.0](https://github.com/algolia/react-instantsearch/compare/v6.36.0...v6.37.0) (2022-10-18) - - -### Features - -* **core:** support react 18 strict mode ([#3653](https://github.com/algolia/react-instantsearch/issues/3653)) ([9174806](https://github.com/algolia/react-instantsearch/commit/9174806a7997a45893a24d149027119f4a0709c3)) - - - -# [6.36.0](https://github.com/algolia/react-instantsearch/compare/v6.35.0...v6.36.0) (2022-10-04) - - -### Features - -* **HierarchicalMenu:** add css class for link of selected menu item ([#3646](https://github.com/algolia/react-instantsearch/issues/3646)) ([980ad70](https://github.com/algolia/react-instantsearch/commit/980ad70c75e970c35c11a10a534dbe3996d6c54c)) -* **useInstantSearch:** expose status & error ([#3645](https://github.com/algolia/react-instantsearch/issues/3645)) ([f436d31](https://github.com/algolia/react-instantsearch/commit/f436d31184f3f75b33a1fdaa19c665e77948df28)) - - - -# [6.35.0](https://github.com/algolia/react-instantsearch/compare/v6.34.0...v6.35.0) (2022-09-29) - - -### Features - -* **hooks-web:** introduce Translations API ([#3638](https://github.com/algolia/react-instantsearch/issues/3638)) ([63b506f](https://github.com/algolia/react-instantsearch/commit/63b506f9dbad284f45ac17210e17c4a2a8f099b6)) - -### Fixes -* **hooks-web:** when searchAsYouType=false, pressing the reset button searches (previously only reset the query) ([#3642](https://github.com/algolia/react-instantsearch/issues/3642)) ([f969deb](https://github.com/algolia/react-instantsearch/commit/f969deb05fd4f53aaa251ff88b52db2224ce0786)) - -# [6.34.0](https://github.com/algolia/react-instantsearch/compare/v6.33.0...v6.34.0) (2022-09-27) - - -### Features - -* **SearchBox:** expose formRef ([#3565](https://github.com/algolia/react-instantsearch/issues/3565)) ([1c2f46d](https://github.com/algolia/react-instantsearch/commit/1c2f46da2d1cf705cfd3946c52aef4ca9ec943d7)) - - - -# [6.33.0](https://github.com/algolia/react-instantsearch/compare/v6.32.1...v6.33.0) (2022-09-15) - - -### Bug Fixes - -* **react-native:** mark as compatible with react 18 ([#3614](https://github.com/algolia/react-instantsearch/issues/3614)) ([2a191a8](https://github.com/algolia/react-instantsearch/commit/2a191a84751127de5a3eb34b59b460a1d1bfe594)) -* **rish:** hide reset button when search is stalled in `SearchBox` ([#3617](https://github.com/algolia/react-instantsearch/issues/3617)) ([93ee9d0](https://github.com/algolia/react-instantsearch/commit/93ee9d0212893cef4842c86b7c78f285aa136be8)) - - -### Features - -* **dependencies:** update instantsearch and helper ([#3622](https://github.com/algolia/react-instantsearch/issues/3622)) ([6773ab1](https://github.com/algolia/react-instantsearch/commit/6773ab169cd74dfe1133e255daade4d57e99d9a4)) - - - -## [6.32.1](https://github.com/algolia/react-instantsearch/compare/v6.32.0...v6.32.1) (2022-08-26) - - -### Bug Fixes - -* **useInstantSearch:** prevent `results` from being `null` when first search is stalled ([#3597](https://github.com/algolia/react-instantsearch/issues/3597)) ([6f71d78](https://github.com/algolia/react-instantsearch/commit/6f71d78868fde55a3f9c4460edc337a1e99df4f9)) - - - -# [6.32.0](https://github.com/algolia/react-instantsearch/compare/v6.31.1...v6.32.0) (2022-08-22) - - -### Features - -* **SearchBox:** introduce `autoFocus` prop ([#3599](https://github.com/algolia/react-instantsearch/issues/3599)) ([99121b9](https://github.com/algolia/react-instantsearch/commit/99121b952fd002cb6dae52af41f08beed8f6c3e2)) - - - -## [6.31.1](https://github.com/algolia/react-instantsearch/compare/v6.31.0...v6.31.1) (2022-08-08) - - -### Bug Fixes - -* **hooks:** prevent widget cleanup on `` unmount ([#3590](https://github.com/algolia/react-instantsearch/issues/3590)) ([d94899d](https://github.com/algolia/react-instantsearch/commit/d94899d1264134f0cb1ca2d266a660f1fb2a588c)) - - - -# [6.31.0](https://github.com/algolia/react-instantsearch/compare/v6.30.3...v6.31.0) (2022-08-03) - - -### Features - -* **hooks:** add `searchAsYouType` option to `` ([#3585](https://github.com/algolia/react-instantsearch/issues/3585)) ([c610385](https://github.com/algolia/react-instantsearch/commit/c610385cb9688b23b3e041e31b9edd60392b341d)) - - - -## [6.30.3](https://github.com/algolia/react-instantsearch/compare/v6.30.2...v6.30.3) (2022-08-01) - - -### Bug Fixes - -* **hooks:** replace `labelText` CSS class with `label` in `` to align with InstantSearch's CSS specifications ([#3583](https://github.com/algolia/react-instantsearch/issues/3583)) ([3e030ae](https://github.com/algolia/react-instantsearch/commit/3e030aedb9f285ff449eb82589bc6fea60b160cb)) - - - -## [6.30.2](https://github.com/algolia/react-instantsearch/compare/v6.30.1...v6.30.2) (2022-07-18) - - -### Bug Fixes - -* **hooks:** type of DynamicWidgets props ([#3566](https://github.com/algolia/react-instantsearch/issues/3566)) ([612c98b](https://github.com/algolia/react-instantsearch/commit/612c98b5a77fb9037185c4b5efda8c07663dbd1a)), closes [#3563](https://github.com/algolia/react-instantsearch/issues/3563) -* **hooks:** use single instance in ([#3561](https://github.com/algolia/react-instantsearch/issues/3561)) ([4c358be](https://github.com/algolia/react-instantsearch/commit/4c358bebfc91451b1610f677f89c595d7a427f1f)) - - - -## [6.30.1](https://github.com/algolia/react-instantsearch/compare/v6.30.0...v6.30.1) (2022-07-12) - - -### Bug Fixes - -* **hooks:** provide state and results APIs from "render" event ([#3554](https://github.com/algolia/react-instantsearch/issues/3554)) ([67d4788](https://github.com/algolia/react-instantsearch/commit/67d4788ab09ec2a57b43d53e8093b8c11120b761)) -* **hooks**: update instantsearch.js dependency ([#3557](https://github.com/algolia/react-instantsearch/issues/3557)) - - - -# [6.30.0](https://github.com/algolia/react-instantsearch/compare/v6.29.0...v6.30.0) (2022-07-05) - - -### Features - -* **core:** update instantsearch and helper ([#3539](https://github.com/algolia/react-instantsearch/issues/3539)) ([0ac2c7a](https://github.com/algolia/react-instantsearch/commit/0ac2c7a3f2e2a827721f5b2b7c69c54560f8574f)) - - - -# [6.29.0](https://github.com/algolia/react-instantsearch/compare/v6.28.0...v6.29.0) (2022-06-21) - - -### Bug Fixes - -* **HierarchicalMenu:** show full hierarchical parent values ([#3521](https://github.com/algolia/react-instantsearch/issues/3521)) ([79c3890](https://github.com/algolia/react-instantsearch/commit/79c3890848175a4d70311e5c3929c902bb953c10)) - - -### Features - -* **core:** sort parameters for improved cache rate ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) -* **core:** support client.search for sffv ([#3528](https://github.com/algolia/react-instantsearch/issues/3528)) ([8320d99](https://github.com/algolia/react-instantsearch/commit/8320d995385e27f271134b014bab6ffa955b3986)) - - - -# [6.28.0](https://github.com/algolia/react-instantsearch/compare/v6.27.0...v6.28.0) (2022-06-15) - - -### Bug Fixes - -* **hooks-server:** import react server via an expression ([#3515](https://github.com/algolia/react-instantsearch/issues/3515)) ([91b96f7](https://github.com/algolia/react-instantsearch/commit/91b96f743b9315ed5ea781681b77fc7f5604ab6e)), closes [#3512](https://github.com/algolia/react-instantsearch/issues/3512) -* **hooks-web:** fix duplicated key in ([#3513](https://github.com/algolia/react-instantsearch/issues/3513)) ([fc94d80](https://github.com/algolia/react-instantsearch/commit/fc94d806daf139f58b234cdc0b450da2efe861ee)) -* **hooks:** mount widgets in SSR to retrieve HTML ([#3518](https://github.com/algolia/react-instantsearch/issues/3518)) ([aa5f9d8](https://github.com/algolia/react-instantsearch/commit/aa5f9d84ddb6e97d05e6ad1baf2c6caa23891281)) -* **types:** allow useInstantSearch to be generic ([#3508](https://github.com/algolia/react-instantsearch/issues/3508)) ([6807232](https://github.com/algolia/react-instantsearch/commit/68072324cf302801502a1b4c3d06703e57b55a97)), closes [algolia/instantsearch.js#5060](https://github.com/algolia/instantsearch.js/issues/5060) -* **types:** support React 18 types ([#3481](https://github.com/algolia/react-instantsearch/issues/3481)) ([74cf8cb](https://github.com/algolia/react-instantsearch/commit/74cf8cb9be8ff3d113b57a50e7083df0d1bc94f2)) - - -### Features - -* **hooks:** introduce `useInstantSearch()` ([#3494](https://github.com/algolia/react-instantsearch/issues/3494)) ([74d522c](https://github.com/algolia/react-instantsearch/commit/74d522c032326658f2a0b8f0001bd593e0085208)) -* **hooks:** support React 18 Strict Mode ([#3514](https://github.com/algolia/react-instantsearch/issues/3514)) ([eeb67c7](https://github.com/algolia/react-instantsearch/commit/eeb67c7b5dc08c696c46d9538f104eeceecef388)) - - - -# [6.27.0](https://github.com/algolia/react-instantsearch/compare/v6.26.0...v6.27.0) (2022-06-07) - - -### Bug Fixes - -* **hooks-web:** don't pass widget props to ui components ([#3501](https://github.com/algolia/react-instantsearch/issues/3501)) ([5bd53c1](https://github.com/algolia/react-instantsearch/commit/5bd53c128ddeeea87f75ae89eb8f2324d476c70e)), closes [#3499](https://github.com/algolia/react-instantsearch/issues/3499) -* **SearchBox-hooks:** correctly pass widget props ([#3499](https://github.com/algolia/react-instantsearch/issues/3499)) ([2cdf906](https://github.com/algolia/react-instantsearch/commit/2cdf90602b7c2c5895124ef64c389ce574154386)), closes [#3498](https://github.com/algolia/react-instantsearch/issues/3498) - - -### Features - -* **hooks:** migrate to `useSyncExternalStore()` ([#3489](https://github.com/algolia/react-instantsearch/issues/3489)) ([81bbdf2](https://github.com/algolia/react-instantsearch/commit/81bbdf28f2d28d8b0081cfd7d9e84c3e33038dd2)) -* **hooks:** upgrade to InstantSearch.js 4.41.0 ([#3502](https://github.com/algolia/react-instantsearch/issues/3502)) ([0b76792](https://github.com/algolia/react-instantsearch/commit/0b76792ea0c4e2ac9fe742810d70ba1aee2a3e79)) - - - -# [6.26.0](https://github.com/algolia/react-instantsearch/compare/v6.25.0...v6.26.0) (2022-05-19) - - -### Features - -* **hooks-web:** expose `sendEvent` to `hitComponent` ([#3476](https://github.com/algolia/react-instantsearch/issues/3476)) ([5cc18d1](https://github.com/algolia/react-instantsearch/commit/5cc18d19d9f22305f33d92e43fd0aca2a5cb949a)) -* **react-instantsearch-core:** allow widgets to set their `$$widgetType` ([#3472](https://github.com/algolia/react-instantsearch/issues/3472)) ([1c436e1](https://github.com/algolia/react-instantsearch/commit/1c436e1429ab4230bbfea7c6d2474d141f5c5c64)) - - - -# [6.25.0](https://github.com/algolia/react-instantsearch/compare/v6.24.3...v6.25.0) (2022-05-17) - - -### Bug Fixes - -* **hooks-highlight:** make sure highlight and snippet don't show html-escaped content ([#3471](https://github.com/algolia/react-instantsearch/issues/3471)) ([c18ddd2](https://github.com/algolia/react-instantsearch/commit/c18ddd25faca37d6bfa3d1c28f6fc22ec5fcf6d8)) -* **hooks-server:** remove faulty UMD build ([#3465](https://github.com/algolia/react-instantsearch/issues/3465)) ([c1ddfe4](https://github.com/algolia/react-instantsearch/commit/c1ddfe408b411551ac8524877a9d65ded8133c42)) - - -### Features - -* **dom-maps:** expose GeoSearchContext ([#3468](https://github.com/algolia/react-instantsearch/issues/3468)) ([a61ff96](https://github.com/algolia/react-instantsearch/commit/a61ff96222bfd4f6301cf93bf95e2fa18b263d3c)), closes [#3448](https://github.com/algolia/react-instantsearch/issues/3448) -* **hooks-server:** support import from React 18 ([#3464](https://github.com/algolia/react-instantsearch/issues/3464)) ([0a13867](https://github.com/algolia/react-instantsearch/commit/0a13867f7dd5a8a18e0957b2072bbde3b02d6490)), closes [#3453](https://github.com/algolia/react-instantsearch/issues/3453) -* **hooks:** make InstantSearch type generic ([#3466](https://github.com/algolia/react-instantsearch/issues/3466)) ([b0905b7](https://github.com/algolia/react-instantsearch/commit/b0905b73bed558c62eedb7ae701be20c2ebe25c9)) - - - -## [6.24.3](https://github.com/algolia/react-instantsearch/compare/v6.24.2...v6.24.3) (2022-05-10) - - -### Bug Fixes - -* **numericmenu:** include range values in comparison with minmax bounds ([#3461](https://github.com/algolia/react-instantsearch/issues/3461)) ([e4c2682](https://github.com/algolia/react-instantsearch/commit/e4c268261dc42a6aa43d985934b53c82f8b71089)) - - - -## [6.24.2](https://github.com/algolia/react-instantsearch/compare/v6.24.1...v6.24.2) (2022-05-05) - - -### Bug Fixes - -* **hooks:** prevent infinite loops from render state ([#3455](https://github.com/algolia/react-instantsearch/issues/3455)) ([1799fc9](https://github.com/algolia/react-instantsearch/commit/1799fc9f78a4a5aafb54df339c3e211ff9187748)) - - - -## [6.24.1](https://github.com/algolia/react-instantsearch/compare/v6.24.0...v6.24.1) (2022-05-03) - - -### Bug Fixes - -* **types:** export correct types for react-instantsearch-hooks-web ([#3454](https://github.com/algolia/react-instantsearch/issues/3454)) ([a863430](https://github.com/algolia/react-instantsearch/commit/a8634306621f7a05a2b3056a6db25ccf8d9eabf0)) - - - -# [6.24.0](https://github.com/algolia/react-instantsearch/compare/v6.23.4...v6.24.0) (2022-04-28) - - -### Features - -* **hooks:** expose DOM components ([#3450](https://github.com/algolia/react-instantsearch/issues/3450)) ([5732e3d](https://github.com/algolia/react-instantsearch/commit/5732e3de732275911f94b26ba9e2c4165bdf77e7)) -* **hooks:** remove experimental warning ([#3446](https://github.com/algolia/react-instantsearch/issues/3446)) ([84c99fe](https://github.com/algolia/react-instantsearch/commit/84c99fe91d6906a877bec620b44c61d762f0ea57)) - - - -## [6.23.4](https://github.com/algolia/react-instantsearch/compare/v6.23.3...v6.23.4) (2022-04-21) - - -### Bug Fixes - -* **hooks:** forbid importing from instantsearch.js root path ([#3437](https://github.com/algolia/react-instantsearch/issues/3437)) ([82ef9ea](https://github.com/algolia/react-instantsearch/commit/82ef9eaaec42bc54f15796b5b031a8656330a45c)) -* **packages:** correctly mark peer dependency ([#3439](https://github.com/algolia/react-instantsearch/issues/3439)) ([51e8818](https://github.com/algolia/react-instantsearch/commit/51e8818fce224819230c8bf6dea2a08d71d9be29)), closes [#3428](https://github.com/algolia/react-instantsearch/issues/3428) - - - -## [6.23.3](https://github.com/algolia/react-instantsearch/compare/v6.23.2...v6.23.3) (2022-04-05) - - -### Bug Fixes - -* **facets:** show raw value in currentRefinements ([#3420](https://github.com/algolia/react-instantsearch/issues/3420)) ([1199ce6](https://github.com/algolia/react-instantsearch/commit/1199ce6bd4152e4b54bd2ee0e1f0c9d81021c7d5)), closes [#3412](https://github.com/algolia/react-instantsearch/issues/3412) -* **multi-index:** correctly set `searching` prop in multi-index result states ([#3419](https://github.com/algolia/react-instantsearch/issues/3419)) ([7f8e97e](https://github.com/algolia/react-instantsearch/commit/7f8e97e31b3dd5e49d3febef673f41f7dfa6d45d)) - - - -## [6.23.2](https://github.com/algolia/react-instantsearch/compare/v6.23.1...v6.23.2) (2022-04-04) - - -### Bug Fixes - -* **refinements:** use escaped value for refining ([#3412](https://github.com/algolia/react-instantsearch/issues/3412)) ([f2f5f6c](https://github.com/algolia/react-instantsearch/commit/f2f5f6cbfaed48a5c494daeb8789e8deebc64293)) -* support React 18 as peer dependency ([#3411](https://github.com/algolia/react-instantsearch/issues/3411)) ([38eb5a6](https://github.com/algolia/react-instantsearch/commit/38eb5a6a8fe92cb763a25f452bea78b189a6a82a)) - - -## [6.23.1](https://algolia/compare/v6.23.0...v6.23.1) (2022-03-30) - - -### Bug Fixes - -* **hooks:** compute initial search parameters from widget ([#3399](https://algolia/issues/3399)) ([b4bd933](https://algolia/commits/b4bd93358598bdc77a1aa858252e6eee23441345)) - - - -# [6.23.0](https://algolia/compare/v6.22.0...v6.23.0) (2022-03-23) - - -### Bug Fixes - -* **ssr:** perform initial multi-index search using a single request ([#3385](https://algolia/issues/3385)) ([b96809e](https://algolia/commits/b96809e5748d298350890647956cb7adbbb55650)) - - -### Features - -* **hooks:** allow additional widget properties to be passed from hooks ([#3359](https://algolia/issues/3359)) ([a047be4](https://algolia/commits/a047be45c7fce7ee28f7d6f61d2fbfa79e3ed2d0)) -* **hooks:** allow useHits and useInfiniteHit to be generic ([#3364](https://algolia/issues/3364)) ([8e66ad3](https://algolia/commits/8e66ad3ad587197c4811c60a5cab475137ca5afb)) -* **hooks:** mark initial results as "artificial" ([#3384](https://algolia/issues/3384)) ([937efdc](https://algolia/commits/937efdc71bae1d99270f8ecb5c5c9c501b3d7769)) - - - -# [6.22.0](https://github.com/algolia/react-instantsearch/compare/v6.21.1...v6.22.0) (2022-02-01) - - -### Bug Fixes - -* **hooks:** enable pause on exceptions on warning ([#3283](https://github.com/algolia/react-instantsearch/issues/3283)) ([ce3a6c3](https://github.com/algolia/react-instantsearch/commit/ce3a6c3f2700a05ae54a91278fd23fa64a97d733)) - - -### Features - -* **hooks:** introduce `useBreadcrumb()` ([#3245](https://github.com/algolia/react-instantsearch/issues/3245)) ([5bfbaaf](https://github.com/algolia/react-instantsearch/commit/5bfbaaf746e7632968ac9b30b73357bcb0b37e91)) - - - -## [6.21.1](https://github.com/algolia/react-instantsearch/compare/v6.21.0...v6.21.1) (2022-01-25) - - -### Bug Fixes - -* **hooks:** apply initial search parameters in useConnector ([#3276](https://github.com/algolia/react-instantsearch/issues/3276)) ([f85d679](https://github.com/algolia/react-instantsearch/commit/f85d6794c31eac61521fd8fc16b75673f02ed75b)) - - - -# [6.21.0](https://github.com/algolia/react-instantsearch/compare/v6.20.0...v6.21.0) (2022-01-24) - - -### Features - -* **hooks-server:** load data twice in the case of dynamic widget usage ([#3259](https://github.com/algolia/react-instantsearch/issues/3259)) ([9b4903b](https://github.com/algolia/react-instantsearch/commit/9b4903b2ea73d9d7e33729b87d9d55990e64312c)) -* **server:** load data twice in the case of dynamic widget usage ([#3268](https://github.com/algolia/react-instantsearch/issues/3268)) ([91cd085](https://github.com/algolia/react-instantsearch/commit/91cd085f9a323ed6b872f3a098f561007a72d0d2)), closes [/github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js#L14-L16](https://github.com//github.com/algolia/react-instantsearch/blob/d459e62f5cae4c98427ab302531873f5ee23d149/packages/react-instantsearch-core/src/core/indexUtils.js/issues/L14-L16) - - - -# [6.20.0](https://github.com/algolia/react-instantsearch/compare/v6.19.0...v6.20.0) (2022-01-18) - - -### Bug Fixes - -* **hooks:** allow importing via require ([#3257](https://github.com/algolia/react-instantsearch/issues/3257)) ([6aa80b3](https://github.com/algolia/react-instantsearch/commit/6aa80b3647567199c3df1b90a07d708b223ce1fd)) - - -### Features - -* **hooks:** implement `useClearRefinements()` ([#3256](https://github.com/algolia/react-instantsearch/issues/3256)) ([930b83d](https://github.com/algolia/react-instantsearch/commit/930b83df4c4bbccbc3118f6ea1001f6a30a3d464)), closes [#3252](https://github.com/algolia/react-instantsearch/issues/3252) -* **hooks:** introduce `` ([#3261](https://github.com/algolia/react-instantsearch/issues/3261)) ([3527b94](https://github.com/algolia/react-instantsearch/commit/3527b9422de48a4a6b4bd752bd643e01cd5011d8)) -* **hooks:** introduce `usePoweredBy()` ([#3251](https://github.com/algolia/react-instantsearch/issues/3251)) ([a97230b](https://github.com/algolia/react-instantsearch/commit/a97230b89e3ba1df9bf2d21a6a9f9a70b45f41b8)) -* **hooks:** introduce `useToggleRefinement()` ([#3248](https://github.com/algolia/react-instantsearch/issues/3248)) ([a561c09](https://github.com/algolia/react-instantsearch/commit/a561c090a268e1c6ca1fa2d5bf72263cc47aa273)) - - - -# [6.19.0](https://github.com/algolia/react-instantsearch/compare/v6.18.0...v6.19.0) (2022-01-05) - - -### Features - -* **hooks:** bundle as es-module ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) -* **dependencies:** update to latest algoliasearch-helper ([#3232](https://github.com/algolia/react-instantsearch/issues/3232)) ([ae4df8a](https://github.com/algolia/react-instantsearch/commit/ae4df8a7dec396e5ea15a4ab2243cd05e05d3ebc)) - - - -# [6.18.0](https://github.com/algolia/react-instantsearch/compare/v6.17.0...v6.18.0) (2021-12-16) - - -### Features - -* **dynamicWidgets:** send facets * and maxValuesPerFacet by default ([#3242](https://github.com/algolia/react-instantsearch/issues/3242)) ([c071776](https://github.com/algolia/react-instantsearch/commit/c07177670ac30dced55250774654e8b2a77b6739)) -* **hooks:** introduce `useNumericMenu()` ([#3237](https://github.com/algolia/react-instantsearch/issues/3237)) ([e3056c9](https://github.com/algolia/react-instantsearch/commit/e3056c9e2c64b5afafb7a736599a5cbf6137575b)) -* **hooks:** introduce `useInfiniteHits()` ([#3224](https://github.com/algolia/react-instantsearch/issues/3224)) ([177ec56](https://github.com/algolia/react-instantsearch/commit/177ec56af274670c2bf8599ba104b5544979bbe8)) - - - -# [6.17.0](https://github.com/algolia/react-instantsearch/compare/v6.16.0...v6.17.0) (2021-12-08) - - -### Bug Fixes - -* **hooks:** throw invariant violations in production ([#3217](https://github.com/algolia/react-instantsearch/issues/3217)) ([6d3f99c](https://github.com/algolia/react-instantsearch/commit/6d3f99ca91f470ee742ddc55e95f57b1f1801d7b)) - - -### Features - -* **hooks:** introduce `useMenu()` ([#3197](https://github.com/algolia/react-instantsearch/issues/3197)) ([15d1cc9](https://github.com/algolia/react-instantsearch/commit/15d1cc993437b111cd5a32f43ee1d2065c639ed4)) -* **hooks:** introduce `useRange()` ([#3198](https://github.com/algolia/react-instantsearch/issues/3198)) ([df1f1c8](https://github.com/algolia/react-instantsearch/commit/df1f1c8109dc684e74d3aee1bf0359f2a0e1b9f4)) -* **hooks:** introduce `` ([#3216](https://github.com/algolia/react-instantsearch/issues/3216)) ([d99aea6](https://github.com/algolia/react-instantsearch/commit/d99aea6cfe9dea86ae6b98ee3762373f4b3843f1)) -* **hooks:** introduce `useDynamicWidgets()` ([#3210](https://github.com/algolia/react-instantsearch/issues/3210)) ([29c2ea2](https://github.com/algolia/react-instantsearch/commit/29c2ea22b91a39d9eb40a044ae9aab85f2612db8)) -* **hooks:** introduce `useQueryRules()` ([#3212](https://github.com/algolia/react-instantsearch/issues/3212)) ([3ef1e1e](https://github.com/algolia/react-instantsearch/commit/3ef1e1e4116b3e58b2c2134d0c60fbb9f40c1501)) -* **hooks:** introduce SSR support ([#3221](https://github.com/algolia/react-instantsearch/issues/3221)) ([0a6b3ec](https://github.com/algolia/react-instantsearch/commit/0a6b3ec61942ad3849c6f078e21b3328679bffff)) -* **hooks:** introduce `useCurrentRefinements()` ([#3222](https://github.com/algolia/react-instantsearch/issues/3222)) ([7ebd8c3](https://github.com/algolia/react-instantsearch/commit/7ebd8c3da8c17b0bd7e0f8deab633b98fa052e7f)) - - - -# [6.16.0](https://github.com/algolia/react-instantsearch/compare/v6.15.0...v6.16.0) (2021-11-22) - - -### Bug Fixes - -* **PoweredBy:** support environments with `window` but no `location` ([#3186](https://github.com/algolia/react-instantsearch/issues/3186)) ([22ff23b](https://github.com/algolia/react-instantsearch/commit/22ff23b67554683567393114c2f53cacec44f4a6)) - - -### Features - -* **DynamicWidgets:** release as stable ([#3090](https://github.com/algolia/react-instantsearch/issues/3090)) ([a4a1d9e](https://github.com/algolia/react-instantsearch/commit/a4a1d9e032b31c611d5d73fdda3a03ad705f5c68)) -* **hooks:** introduce `usePagination()` ([#3182](https://github.com/algolia/react-instantsearch/issues/3182)) ([d8b1b86](https://github.com/algolia/react-instantsearch/commit/d8b1b867bb598e801f1350e81b4a4220a8e528d7)) -* **hooks:** introduce `useSortBy()` ([#3190](https://github.com/algolia/react-instantsearch/issues/3190)) ([5cce33b](https://github.com/algolia/react-instantsearch/commit/5cce33b48032548fed76b592ee0201e3c42fc3c4)) -* **hooks:** introduce `useHierarchicalMenu()` ([#3199](https://github.com/algolia/react-instantsearch/issues/3199)) ([b347061](https://github.com/algolia/react-instantsearch/commit/b3470611b962ef55c55576c65a6307abc54e5efd)) - - - -# [6.15.0](https://github.com/algolia/react-instantsearch/compare/v6.14.0...v6.15.0) (2021-10-27) - - -### Bug Fixes - -* **metadata:** stricter detection of user agent ([#3184](https://github.com/algolia/react-instantsearch/issues/3184)) ([994c8ae](https://github.com/algolia/react-instantsearch/commit/994c8ae055fc23a1a067d111d2f4727b1c7bf8ca)) - - -### Features - -* **hooks:** introduce `useConfigure()` ([#3181](https://github.com/algolia/react-instantsearch/issues/3181)) ([aa2eb9b](https://github.com/algolia/react-instantsearch/commit/aa2eb9baec6335f8a3523ee8b9b761a217cfc734)) - - - -# [6.14.0](https://github.com/algolia/react-instantsearch/compare/v6.13.0...v6.14.0) (2021-10-26) - - -### Features - -* **dependencies:** update algoliasearch-helper ([#3176](https://github.com/algolia/react-instantsearch/issues/3176)) ([a8708a3](https://github.com/algolia/react-instantsearch/commit/a8708a33f31632000bc827b076539b1cca7adf6f)) -* **metadata:** expose widget information ([#3145](https://github.com/algolia/react-instantsearch/issues/3145)) ([46cddf8](https://github.com/algolia/react-instantsearch/commit/46cddf8fcc0291beaa34b04da7aaaa7f2566e52e)) - - - -# [6.13.0](https://github.com/algolia/react-instantsearch/compare/v6.12.1...v6.13.0) (2021-10-19) - -This is the initial release of the experimental **React InstantSearch Hooks** package. Check out the [**Getting Started**](https://github.com/algolia/react-instantsearch/blob/e8d72cb1c7c45300ef7c273f1f163beb6dc57622/packages/react-instantsearch-hooks/README.md#getting-started) guide. - -### Bug Fixes - -- **core:** accept objects for `hitComponent` ([#3087](https://github.com/algolia/react-instantsearch/issues/3087)) ([4ae23d4](https://github.com/algolia/react-instantsearch/commit/4ae23d432a01ccbefff1fcdc865120aeca4d3efc)) - -### Features - -- **hooks:** add InstantSearch and Index components ([#3133](https://github.com/algolia/react-instantsearch/issues/3133)) ([8e3370d](https://github.com/algolia/react-instantsearch/commit/8e3370ddb7d5e42b8b9a5ff6a1e4255490de7dbe)) -- **hooks:** bootstrap Core package ([#3132](https://github.com/algolia/react-instantsearch/issues/3132)) ([d459e62](https://github.com/algolia/react-instantsearch/commit/d459e62f5cae4c98427ab302531873f5ee23d149)) -- **hooks:** display experimental warning ([#3149](https://github.com/algolia/react-instantsearch/issues/3149)) ([623577c](https://github.com/algolia/react-instantsearch/commit/623577c50cd0c04cd87f719edafdcfa04b5527b6)) -- **hooks:** export types ([#3159](https://github.com/algolia/react-instantsearch/issues/3159)) ([182348b](https://github.com/algolia/react-instantsearch/commit/182348b4a901823a7a41aee5d2b3bdc025cce48f)) -- **hooks:** expose `displayName` on Contexts ([#3168](https://github.com/algolia/react-instantsearch/issues/3168)) ([dafd3c6](https://github.com/algolia/react-instantsearch/commit/dafd3c66d05fbec09ebf907209ac25f55804e6f5)) -- **hooks:** friendly error when using Hooks with Core ([#3150](https://github.com/algolia/react-instantsearch/issues/3150)) ([d547ccf](https://github.com/algolia/react-instantsearch/commit/d547ccf7951299e2f6b1771e02fce052696ff65a)) -- **hooks:** introduce `useConnector()` ([#3137](https://github.com/algolia/react-instantsearch/issues/3137)) ([53e8afd](https://github.com/algolia/react-instantsearch/commit/53e8afd093b9950351467a16b82d528207ac34d2)) -- **hooks:** introduce `useHits()` ([#3147](https://github.com/algolia/react-instantsearch/issues/3147)) ([cc25cff](https://github.com/algolia/react-instantsearch/commit/cc25cff06e5ec216cba40fb8261372bc327001b6)) -- **hooks:** introduce `useRefinementList()` ([#3152](https://github.com/algolia/react-instantsearch/issues/3152)) ([0385cd9](https://github.com/algolia/react-instantsearch/commit/0385cd971635a8423ad687fab451d0778358389e)) -- **hooks:** introduce `useSearchBox()` ([#3146](https://github.com/algolia/react-instantsearch/issues/3146)) ([0d2c7f9](https://github.com/algolia/react-instantsearch/commit/0d2c7f9bd25b88cf725a1babd3b228ac804644c7)) -- **hooks:** trigger single network request on load ([#3167](https://github.com/algolia/react-instantsearch/issues/3167)) ([ff1ea49](https://github.com/algolia/react-instantsearch/commit/ff1ea49079a7800fd61ba99ceeb74b9f513eb99d)) -- **hooks:** type `useConnector()` return as render state ([#3169](https://github.com/algolia/react-instantsearch/issues/3169)) ([a801468](https://github.com/algolia/react-instantsearch/commit/a80146860164a092d2c90ee0aa4fcef88d5b675f)) -- **hooks:** update GitHub bug reports link ([#3157](https://github.com/algolia/react-instantsearch/issues/3157)) ([568b5c8](https://github.com/algolia/react-instantsearch/commit/568b5c83849a3927417907706656c3835163f216)) - - - -## [6.12.1](https://github.com/algolia/react-instantsearch/compare/v6.12.0...v6.12.1) (2021-08-02) - - -### Bug Fixes - -* **server side rendering:** return a value from mock currentRefinement/metadata ([#3078](https://github.com/algolia/react-instantsearch/issues/3078)) ([09f802b](https://github.com/algolia/react-instantsearch/commit/09f802b)) - - - -# [6.12.0](https://github.com/algolia/react-instantsearch/compare/v6.11.2...v6.12.0) (2021-07-06) - - -### Bug Fixes - -* **HitsPerPage:** Adds id prop to HitsPerPage, Select components ([#3072](https://github.com/algolia/react-instantsearch/issues/3072)) ([bc75d75](https://github.com/algolia/react-instantsearch/commit/bc75d75)) -* **MenuSelect:** Adds id prop to MenuSelect ([#3073](https://github.com/algolia/react-instantsearch/issues/3073)) ([fddaaef](https://github.com/algolia/react-instantsearch/commit/fddaaef)) -* **SearchBox:** Adds inputId prop to SearchBox ([#3074](https://github.com/algolia/react-instantsearch/issues/3074)) ([a05f6a4](https://github.com/algolia/react-instantsearch/commit/a05f6a4)) -* **SortBy:** Adds `id` prop to `SortBy`, `Select` components ([#3068](https://github.com/algolia/react-instantsearch/issues/3068)) ([1f2797f](https://github.com/algolia/react-instantsearch/commit/1f2797f)) - - -### Features - -* **DynamicWidgets:** add implementation ([#3056](https://github.com/algolia/react-instantsearch/issues/3056)) ([691ef87](https://github.com/algolia/react-instantsearch/commit/691ef87)) -* **facets:** add a new option "facetOrdering" to Menu, RefinementList & HierarchicalMenu ([#3067](https://github.com/algolia/react-instantsearch/issues/3067)) ([731d9ba](https://github.com/algolia/react-instantsearch/commit/731d9ba)) - - - -## [6.11.2](https://github.com/algolia/react-instantsearch/compare/v6.11.1...v6.11.2) (2021-06-28) - - -### Bug Fixes - -* **maps:** leave zoom in place if the bounds did not change ([#3050](https://github.com/algolia/react-instantsearch/issues/3050)) ([c430598](https://github.com/algolia/react-instantsearch/commit/c430598)) - - - -## [6.11.1](https://github.com/algolia/react-instantsearch/compare/v6.11.0...v6.11.1) (2021-06-09) - - -### Bug Fixes - -* **RefinementList:** prevent searchable component to refine on empty list ([#3059](https://github.com/algolia/react-instantsearch/issues/3059)) ([04f3644](https://github.com/algolia/react-instantsearch/commit/04f3644)) - - - -# [6.11.0](https://github.com/algolia/react-instantsearch/compare/v6.10.3...v6.11.0) (2021-05-04) - - -### Features - -* **connectNumericMenu:** add support for floating point values ([#3047](https://github.com/algolia/react-instantsearch/issues/3047)) ([091bf57](https://github.com/algolia/react-instantsearch/commit/091bf57)) - - - -## [6.10.3](https://github.com/algolia/react-instantsearch/compare/v6.10.2...v6.10.3) (2021-03-03) - - -### Bug Fixes - -* **RelevantSort:** Rename `SmartSort` widget to `RelevantSort` ([#3026](https://github.com/algolia/react-instantsearch/issues/3026)) ([47d11bf](https://github.com/algolia/react-instantsearch/commit/47d11bf)) - - - -## [6.10.2](https://github.com/algolia/react-instantsearch/compare/v6.10.1...v6.10.2) (2021-03-03) - - -### Bug Fixes - -* **infiniteHits:** fix stale hits issue ([#3021](https://github.com/algolia/react-instantsearch/issues/3021)) ([a9a29c7](https://github.com/algolia/react-instantsearch/commit/a9a29c7)) - - - -## [6.10.1](https://github.com/algolia/react-instantsearch/compare/v6.10.0...v6.10.1) (2021-03-02) - - -### Bug Fixes - -* **SmartSort:** make `textComponent` and `buttonTextComponent` optional ([#3014](https://github.com/algolia/react-instantsearch/issues/3014)) ([682ee6d](https://github.com/algolia/react-instantsearch/commit/682ee6d)) - - - -# [6.10.0](https://github.com/algolia/react-instantsearch/compare/v6.9.0...v6.10.0) (2021-02-23) - - -### Bug Fixes - -* **infiniteHits:** do not cache the cached hits ([#3011](https://github.com/algolia/react-instantsearch/issues/3011)) ([b56f5f7](https://github.com/algolia/react-instantsearch/commit/b56f5f7)) - - -### Features - -* **smartSort:** add widget ([#3009](https://github.com/algolia/react-instantsearch/issues/3009)) ([4cc8412](https://github.com/algolia/react-instantsearch/commit/4cc8412)), closes [#3010](https://github.com/algolia/react-instantsearch/issues/3010) - - - -# [6.9.0](https://github.com/algolia/react-instantsearch/compare/v6.8.3...v6.9.0) (2021-02-03) - - -### Features - -* **answers:** add `EXPERIMENTAL_Answers` widget ([#2996](https://github.com/algolia/react-instantsearch/issues/2996)) ([55e4191](https://github.com/algolia/react-instantsearch/commit/55e4191)), closes [#3005](https://github.com/algolia/react-instantsearch/issues/3005) - - - -## [6.8.3](https://github.com/algolia/react-instantsearch/compare/v6.8.2...v6.8.3) (2021-01-22) - - -### Bug Fixes - -* upgrade prop-types dependency to 15.6+ ([#3003](https://github.com/algolia/react-instantsearch/issues/3003)) ([fc03496](https://github.com/algolia/react-instantsearch/commit/fc03496)) - - - -## [6.8.2](https://github.com/algolia/react-instantsearch/compare/v6.8.1...v6.8.2) (2020-10-21) - - -### Bug Fixes - -* **ssr:** provide metadata default value ([0a2f34c](https://github.com/algolia/react-instantsearch/commit/0a2f34c)) - - - -## [6.8.1](https://github.com/algolia/react-instantsearch/compare/v6.8.0...v6.8.1) (2020-10-14) - - -### Bug Fixes - -* **ssr:** hydrate metadata with a value ([9249c19](https://github.com/algolia/react-instantsearch/commit/9249c19)) - - - -# [6.8.0](https://github.com/algolia/react-instantsearch/compare/v6.7.0...v6.8.0) (2020-10-14) - - -### Bug Fixes - -* **ssr:** make sure metadata is available on initial render ([#2973](https://github.com/algolia/react-instantsearch/issues/2973)) ([be43b65](https://github.com/algolia/react-instantsearch/commit/be43b65)), closes [#2972](https://github.com/algolia/react-instantsearch/issues/2972) -* add missing dependencies ([#2975](https://github.com/algolia/react-instantsearch/issues/2975)) ([22ecb3c](https://github.com/algolia/react-instantsearch/commit/22ecb3c)) -* **ConfigureRelatedItems:** support nested attributes ([#2967](https://github.com/algolia/react-instantsearch/issues/2967)) ([86dfe86](https://github.com/algolia/react-instantsearch/commit/86dfe86)) -* **ssr:** allow "params" to be optional in custom clients ([#2961](https://github.com/algolia/react-instantsearch/issues/2961)) ([c3e3d2e](https://github.com/algolia/react-instantsearch/commit/c3e3d2e)), closes [#2958](https://github.com/algolia/react-instantsearch/issues/2958) - - - -# [6.7.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.7.0) (2020-07-20) - - -### Bug Fixes - -* **core:** appending successful index search results by returning new object reference ([#2953](https://github.com/algolia/react-instantsearch/issues/2953)) ([0a711a7](https://github.com/algolia/react-instantsearch/commit/0a711a7)) -* **ssr:** remove second instance of "query" in the response "params" for SSR ([#2945](https://github.com/algolia/react-instantsearch/issues/2945)) ([bf837c5](https://github.com/algolia/react-instantsearch/commit/bf837c5)), closes [#2941](https://github.com/algolia/react-instantsearch/issues/2941) - - -### Features - -* **infinite-hits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.6.0](https://github.com/algolia/react-instantsearch/compare/v6.5.0...v6.6.0) (2020-06-15) - - -### Features - -* **infiniteHits:** support cache ([#2921](https://github.com/algolia/react-instantsearch/issues/2921)) ([7b26adc](https://github.com/algolia/react-instantsearch/commit/7b26adc)) - - - -# [6.5.0](https://github.com/algolia/react-instantsearch/compare/v6.4.0...v6.5.0) (2020-05-18) - - -### Bug Fixes - -* **connectQueryRules:** fix crash when using connectQueryRules with multiple indexes ([#2903](https://github.com/algolia/react-instantsearch/issues/2903)) ([c66d612](https://github.com/algolia/react-instantsearch/commit/c66d612)) -* **core:** fix maximum call stack size exceeded ([#2926](https://github.com/algolia/react-instantsearch/issues/2926)) ([7e883df](https://github.com/algolia/react-instantsearch/commit/7e883df)) - - -### Features - -* **SearchBox:** provide input element ref ([#2913](https://github.com/algolia/react-instantsearch/issues/2913)) ([b41bff2](https://github.com/algolia/react-instantsearch/commit/b41bff2)) - - - -# [6.4.0](https://github.com/algolia/react-instantsearch/compare/v6.3.0...v6.4.0) (2020-03-18) - - -### Bug Fixes - -* **deps:** fix "too much recursion" error with circular deps ([#2899](https://github.com/algolia/react-instantsearch/issues/2899)) ([c5f27a1](https://github.com/algolia/react-instantsearch/commit/c5f27a1)) - - - -# [6.3.0](https://github.com/algolia/react-instantsearch/compare/v6.2.0...v6.3.0) (2020-01-30) - - -### Features - -* **algoliasearch:** add support for algoliasearch v4 ([#2890](https://github.com/algolia/react-instantsearch/issues/2890)) ([c6c7382](https://github.com/algolia/react-instantsearch/commit/c6c7382)) - - - -# [6.2.0](https://github.com/algolia/react-instantsearch/compare/v6.1.0...v6.2.0) (2020-01-20) - - -### Bug Fixes - -* **deps:** update dependency algoliasearch to v3.35.1 ([#2802](https://github.com/algolia/react-instantsearch/issues/2802)) ([cfb91f0](https://github.com/algolia/react-instantsearch/commit/cfb91f0)) -* **widgets:** rename `ExperimentalConfigureRelatedItems` compon… ([#2891](https://github.com/algolia/react-instantsearch/issues/2891)) ([b910df2](https://github.com/algolia/react-instantsearch/commit/b910df2)) - - -### Features - -* **insights:** add getInsightsAnonymousUserToken helper ([#2887](https://github.com/algolia/react-instantsearch/issues/2887)) ([b5fe4f7](https://github.com/algolia/react-instantsearch/commit/b5fe4f7)) -* **widgets:** introduce `ConfigureRelatedItems` as experimental ([#2880](https://github.com/algolia/react-instantsearch/issues/2880)) ([923cd43](https://github.com/algolia/react-instantsearch/commit/923cd43)) - - - -# [6.1.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0...v6.1.0) (2019-12-17) - - -### Bug Fixes - -* **connectNumericMenu:** support numeric refinement 0 ([#2882](https://github.com/algolia/react-instantsearch/issues/2882)) ([30bd9fd](https://github.com/algolia/react-instantsearch/commit/30bd9fd)) -* **deps:** update dependency next to v9.1.1 ([9d49d33](https://github.com/algolia/react-instantsearch/commit/9d49d33)) -* **helper:** rely on stable version of algoliasearch-helper ([#2871](https://github.com/algolia/react-instantsearch/issues/2871)) ([e3531a1](https://github.com/algolia/react-instantsearch/commit/e3531a1)) - - -### Features - -* **insights:** show an error when 'clickAnalytics: true' is missing. ([#2877](https://github.com/algolia/react-instantsearch/issues/2877)) ([621656a](https://github.com/algolia/react-instantsearch/commit/621656a)) -* **voice:** add additionalQueryParameters ([#2366](https://github.com/algolia/react-instantsearch/issues/2366)) ([3a45b2c](https://github.com/algolia/react-instantsearch/commit/3a45b2c)) - - - -# [6.0.0](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.2...v6.0.0) (2019-10-28) - - - -# [6.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2019-10-25) - - -### Bug Fixes - -* serialize cache value on hydrate ([#2862](https://github.com/algolia/react-instantsearch/issues/2862)) ([3319665](https://github.com/algolia/react-instantsearch/commit/3319665)), closes [#2828](https://github.com/algolia/react-instantsearch/issues/2828) - - - -# [6.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.1) (2019-10-18) - - -### Bug Fixes - -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **deps:** update dependency antd to v3.19.3 ([#2530](https://github.com/algolia/react-instantsearch/issues/2530)) ([73636c5](https://github.com/algolia/react-instantsearch/commit/73636c5)) -* **deps:** update dependency antd to v3.19.4 ([#2559](https://github.com/algolia/react-instantsearch/issues/2559)) ([c3e8267](https://github.com/algolia/react-instantsearch/commit/c3e8267)) -* **deps:** update dependency antd to v3.19.5 ([#2560](https://github.com/algolia/react-instantsearch/issues/2560)) ([72efd31](https://github.com/algolia/react-instantsearch/commit/72efd31)) -* **deps:** update dependency antd to v3.19.6 ([#2564](https://github.com/algolia/react-instantsearch/issues/2564)) ([654f986](https://github.com/algolia/react-instantsearch/commit/654f986)) -* **deps:** update dependency antd to v3.19.7 ([#2573](https://github.com/algolia/react-instantsearch/issues/2573)) ([7e963ad](https://github.com/algolia/react-instantsearch/commit/7e963ad)) -* **deps:** update dependency antd to v3.19.8 ([#2584](https://github.com/algolia/react-instantsearch/issues/2584)) ([34dd9b2](https://github.com/algolia/react-instantsearch/commit/34dd9b2)) -* **deps:** update dependency antd to v3.20.0 ([#2611](https://github.com/algolia/react-instantsearch/issues/2611)) ([b976c67](https://github.com/algolia/react-instantsearch/commit/b976c67)) -* **deps:** update dependency antd to v3.20.1 ([#2635](https://github.com/algolia/react-instantsearch/issues/2635)) ([792ad9c](https://github.com/algolia/react-instantsearch/commit/792ad9c)) -* **deps:** update dependency antd to v3.20.2 ([#2655](https://github.com/algolia/react-instantsearch/issues/2655)) ([301c2d8](https://github.com/algolia/react-instantsearch/commit/301c2d8)) -* **deps:** update dependency antd to v3.20.3 ([#2658](https://github.com/algolia/react-instantsearch/issues/2658)) ([d078e70](https://github.com/algolia/react-instantsearch/commit/d078e70)) -* **deps:** update dependency antd to v3.20.5 ([#2686](https://github.com/algolia/react-instantsearch/issues/2686)) ([42ef821](https://github.com/algolia/react-instantsearch/commit/42ef821)) -* **deps:** update dependency antd to v3.20.6 ([#2711](https://github.com/algolia/react-instantsearch/issues/2711)) ([927fbfe](https://github.com/algolia/react-instantsearch/commit/927fbfe)) -* **deps:** update dependency antd to v3.20.7 ([#2712](https://github.com/algolia/react-instantsearch/issues/2712)) ([1830952](https://github.com/algolia/react-instantsearch/commit/1830952)) -* **deps:** update dependency antd to v3.21.1 ([#2736](https://github.com/algolia/react-instantsearch/issues/2736)) ([39a51a6](https://github.com/algolia/react-instantsearch/commit/39a51a6)) -* **deps:** update dependency antd to v3.21.2 ([#2738](https://github.com/algolia/react-instantsearch/issues/2738)) ([a7a998a](https://github.com/algolia/react-instantsearch/commit/a7a998a)) -* **deps:** update dependency antd to v3.21.4 ([#2747](https://github.com/algolia/react-instantsearch/issues/2747)) ([60012be](https://github.com/algolia/react-instantsearch/commit/60012be)) -* **deps:** update dependency antd to v3.22.0 ([#2758](https://github.com/algolia/react-instantsearch/issues/2758)) ([9cda468](https://github.com/algolia/react-instantsearch/commit/9cda468)) -* **deps:** update dependency antd to v3.22.2 ([#2791](https://github.com/algolia/react-instantsearch/issues/2791)) ([ff1f5d9](https://github.com/algolia/react-instantsearch/commit/ff1f5d9)) -* **deps:** update dependency antd to v3.23.2 ([#2814](https://github.com/algolia/react-instantsearch/issues/2814)) ([a190410](https://github.com/algolia/react-instantsearch/commit/a190410)) -* **deps:** update dependency lodash to v4.17.13 ([c4974cf](https://github.com/algolia/react-instantsearch/commit/c4974cf)) -* **deps:** update dependency lodash to v4.17.14 ([#2647](https://github.com/algolia/react-instantsearch/issues/2647)) ([a2d2dd5](https://github.com/algolia/react-instantsearch/commit/a2d2dd5)) -* **deps:** update dependency lodash to v4.17.15 ([#2684](https://github.com/algolia/react-instantsearch/issues/2684)) ([354143f](https://github.com/algolia/react-instantsearch/commit/354143f)) -* **deps:** update dependency next to v9 ([#2638](https://github.com/algolia/react-instantsearch/issues/2638)) ([d22f61d](https://github.com/algolia/react-instantsearch/commit/d22f61d)) -* **deps:** update dependency next to v9.0.1 ([#2652](https://github.com/algolia/react-instantsearch/issues/2652)) ([2c2dab9](https://github.com/algolia/react-instantsearch/commit/2c2dab9)) -* **deps:** update dependency next to v9.0.2 ([#2662](https://github.com/algolia/react-instantsearch/issues/2662)) ([6fa4c5e](https://github.com/algolia/react-instantsearch/commit/6fa4c5e)) -* **deps:** update dependency next to v9.0.3 ([#2724](https://github.com/algolia/react-instantsearch/issues/2724)) ([f51b04b](https://github.com/algolia/react-instantsearch/commit/f51b04b)) -* **deps:** update dependency next to v9.0.4 ([#2767](https://github.com/algolia/react-instantsearch/issues/2767)) ([9af9180](https://github.com/algolia/react-instantsearch/commit/9af9180)) -* **deps:** update dependency next to v9.0.5 ([#2789](https://github.com/algolia/react-instantsearch/issues/2789)) ([0a75f41](https://github.com/algolia/react-instantsearch/commit/0a75f41)) -* **deps:** update dependency qs to v6.8.0 ([#2757](https://github.com/algolia/react-instantsearch/issues/2757)) ([8bffb87](https://github.com/algolia/react-instantsearch/commit/8bffb87)) -* **deps:** update dependency react-compound-slider to v2.1.0 ([#2610](https://github.com/algolia/react-instantsearch/issues/2610)) ([3389ee5](https://github.com/algolia/react-instantsearch/commit/3389ee5)) -* **deps:** update dependency react-compound-slider to v2.2.0 ([#2649](https://github.com/algolia/react-instantsearch/issues/2649)) ([7b81af1](https://github.com/algolia/react-instantsearch/commit/7b81af1)) -* **deps:** update dependency react-native-vector-icons to v6.5.0 ([#2520](https://github.com/algolia/react-instantsearch/issues/2520)) ([5f7f5b6](https://github.com/algolia/react-instantsearch/commit/5f7f5b6)) -* **deps:** update dependency react-native-vector-icons to v6.6.0 ([#2599](https://github.com/algolia/react-instantsearch/issues/2599)) ([b6bb199](https://github.com/algolia/react-instantsearch/commit/b6bb199)) -* **deps:** update dependency react-router-dom to v5.0.1 ([#2506](https://github.com/algolia/react-instantsearch/issues/2506)) ([d762230](https://github.com/algolia/react-instantsearch/commit/d762230)) -* **highlight:** switch to index as key ([#2691](https://github.com/algolia/react-instantsearch/issues/2691)) ([17e75d1](https://github.com/algolia/react-instantsearch/commit/17e75d1)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### chore - -* **release:** 6.0.0-beta.1 ([#2861](https://github.com/algolia/react-instantsearch/issues/2861)) ([cb56ca0](https://github.com/algolia/react-instantsearch/commit/cb56ca0)), closes [#2023](https://github.com/algolia/react-instantsearch/issues/2023) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2178](https://github.com/algolia/react-instantsearch/issues/2178) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2203](https://github.com/algolia/react-instantsearch/issues/2203) [#2432](https://github.com/algolia/react-instantsearch/issues/2432) [#2444](https://github.com/algolia/react-instantsearch/issues/2444) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2454](https://github.com/algolia/react-instantsearch/issues/2454) [#2455](https://github.com/algolia/react-instantsearch/issues/2455) [#2459](https://github.com/algolia/react-instantsearch/issues/2459) [#2458](https://github.com/algolia/react-instantsearch/issues/2458) [#2460](https://github.com/algolia/react-instantsearch/issues/2460) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2446](https://github.com/algolia/react-instantsearch/issues/2446) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2466](https://github.com/algolia/react-instantsearch/issues/2466) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2442](https://github.com/algolia/react-instantsearch/issues/2442) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2555](https://github.com/algolia/react-instantsearch/issues/2555) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2349](https://github.com/algolia/react-instantsearch/issues/2349) [#2570](https://github.com/algolia/react-instantsearch/issues/2570) [#2462](https://github.com/algolia/react-instantsearch/issues/2462) [#2600](https://github.com/algolia/react-instantsearch/issues/2600) [#2468](https://github.com/algolia/react-instantsearch/issues/2468) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2621](https://github.com/algolia/react-instantsearch/issues/2621) [#2627](https://github.com/algolia/react-instantsearch/issues/2627) [#2644](https://github.com/algolia/react-instantsearch/issues/2644) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2645](https://github.com/algolia/react-instantsearch/issues/2645) [#2339](https://github.com/algolia/react-instantsearch/issues/2339) [#2643](https://github.com/algolia/react-instantsearch/issues/2643) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2722](https://github.com/algolia/react-instantsearch/issues/2722) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2379](https://github.com/algolia/react-instantsearch/issues/2379) [#2289](https://github.com/algolia/react-instantsearch/issues/2289) [#2290](https://github.com/algolia/react-instantsearch/issues/2290) [#2304](https://github.com/algolia/react-instantsearch/issues/2304) [#2307](https://github.com/algolia/react-instantsearch/issues/2307) [#2314](https://github.com/algolia/react-instantsearch/issues/2314) [#2288](https://github.com/algolia/react-instantsearch/issues/2288) [#2305](https://github.com/algolia/react-instantsearch/issues/2305) [#2701](https://github.com/algolia/react-instantsearch/issues/2701) [#2568](https://github.com/algolia/react-instantsearch/issues/2568) [#2357](https://github.com/algolia/react-instantsearch/issues/2357) [#2552](https://github.com/algolia/react-instantsearch/issues/2552) [#2530](https://github.com/algolia/react-instantsearch/issues/2530) [#2559](https://github.com/algolia/react-instantsearch/issues/2559) [#2560](https://github.com/algolia/react-instantsearch/issues/2560) [#2564](https://github.com/algolia/react-instantsearch/issues/2564) [#2573](https://github.com/algolia/react-instantsearch/issues/2573) [#2584](https://github.com/algolia/react-instantsearch/issues/2584) [#2611](https://github.com/algolia/react-instantsearch/issues/2611) [#2635](https://github.com/algolia/react-instantsearch/issues/2635) [#2655](https://github.com/algolia/react-instantsearch/issues/2655) [#2658](https://github.com/algolia/react-instantsearch/issues/2658) [#2686](https://github.com/algolia/react-instantsearch/issues/2686) [#2711](https://github.com/algolia/react-instantsearch/issues/2711) [#2712](https://github.com/algolia/react-instantsearch/issues/2712) [#2736](https://github.com/algolia/react-instantsearch/issues/2736) [#2738](https://github.com/algolia/react-instantsearch/issues/2738) [#2747](https://github.com/algolia/react-instantsearch/issues/2747) [#2758](https://github.com/algolia/react-instantsearch/issues/2758) [#2647](https://github.com/algolia/react-instantsearch/issues/2647) [#2684](https://github.com/algolia/react-instantsearch/issues/2684) [#2638](https://github.com/algolia/react-instantsearch/issues/2638) [#2652](https://github.com/algolia/react-instantsearch/issues/2652) [#2662](https://github.com/algolia/react-instantsearch/issues/2662) [#2724](https://github.com/algolia/react-instantsearch/issues/2724) [#2767](https://github.com/algolia/react-instantsearch/issues/2767) [#2757](https://github.com/algolia/react-instantsearch/issues/2757) [#2610](https://github.com/algolia/react-instantsearch/issues/2610) [#2649](https://github.com/algolia/react-instantsearch/issues/2649) [#2520](https://github.com/algolia/react-instantsearch/issues/2520) [#2599](https://github.com/algolia/react-instantsearch/issues/2599) [#2506](https://github.com/algolia/react-instantsearch/issues/2506) [#2467](https://github.com/algolia/react-instantsearch/issues/2467) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2690](https://github.com/algolia/react-instantsearch/issues/2690) [#2688](https://github.com/algolia/react-instantsearch/issues/2688) [#2626](https://github.com/algolia/react-instantsearch/issues/2626) [#2726](https://github.com/algolia/react-instantsearch/issues/2726) [#2535](https://github.com/algolia/react-instantsearch/issues/2535) [#2461](https://github.com/algolia/react-instantsearch/issues/2461) [#2434](https://github.com/algolia/react-instantsearch/issues/2434) [#2687](https://github.com/algolia/react-instantsearch/issues/2687) [#2338](https://github.com/algolia/react-instantsearch/issues/2338) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) [#2834](https://github.com/algolia/react-instantsearch/issues/2834) [#2845](https://github.com/algolia/react-instantsearch/issues/2845) [#2842](https://github.com/algolia/react-instantsearch/issues/2842) [#2852](https://github.com/algolia/react-instantsearch/issues/2852) [#2853](https://github.com/algolia/react-instantsearch/issues/2853) - - -### BREAKING CHANGES - -* **release:** translation will render default value if passed undefined as value - -* chore(lodash): remove imports - -* fix(translation): allow undefined value to be passed on purpose -* **release:** no longer do we allow paths like `attribute[5].something`, or other indexed forms, only `.` is allowed as special key. - -All existing tests still pass, and we never documented you could use `lodash.get` patterns other than `.`. - -* feat(get): accept array & bracked-separated string - -moved to utils at the same time - -* fix typo - -* feedback: test for undefined behaviour - -* chore(size): update expectation - -this will go down afterwards, but for now there's some more duplication - - - -# [6.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.7.0...v6.0.0-beta.0) (2019-08-21) - -[Migration guide](MIGRATION.md) - -### Bug Fixes - -* **react 17 compat:** upgrade RangeInput lifecycle ([#2289](https://github.com/algolia/react-instantsearch/issues/2289)) ([110b1af](https://github.com/algolia/react-instantsearch/commit/110b1af)) -* **react 17 compat:** upgrade RangeSlider lifecycle ([#2290](https://github.com/algolia/react-instantsearch/issues/2290)) ([69a7f53](https://github.com/algolia/react-instantsearch/commit/69a7f53)) -* **connectToggleRefinement:** cast currentRefinement to boolean ([#2701](https://github.com/algolia/react-instantsearch/issues/2701)) ([db934fd](https://github.com/algolia/react-instantsearch/commit/db934fd)) -* **core:** searchState can be non-Object object ([#2722](https://github.com/algolia/react-instantsearch/issues/2722)) ([dea493c](https://github.com/algolia/react-instantsearch/commit/dea493c)), closes [#2568](https://github.com/algolia/react-instantsearch/issues/2568) -* **createConnector:** new React life cycles ([#2357](https://github.com/algolia/react-instantsearch/issues/2357)) ([fc10640](https://github.com/algolia/react-instantsearch/commit/fc10640)) -* **createInstantSearchManager:** do not trigger search on index update ([#2552](https://github.com/algolia/react-instantsearch/issues/2552)) ([e209362](https://github.com/algolia/react-instantsearch/commit/e209362)) -* **geo:** check for undefined in isEqual ([#2643](https://github.com/algolia/react-instantsearch/issues/2643)) ([a544231](https://github.com/algolia/react-instantsearch/commit/a544231)), closes [#2467](https://github.com/algolia/react-instantsearch/issues/2467) -* **geo:** remove lifecycle compat ([#2644](https://github.com/algolia/react-instantsearch/issues/2644)) ([2b2b898](https://github.com/algolia/react-instantsearch/commit/2b2b898)), closes [#2626](https://github.com/algolia/react-instantsearch/issues/2626) -* **highlight:** switch to index as key ([#2690](https://github.com/algolia/react-instantsearch/issues/2690)) ([51de682](https://github.com/algolia/react-instantsearch/commit/51de682)), closes [#2688](https://github.com/algolia/react-instantsearch/issues/2688) -* **peerDependencies:** update React ([#2626](https://github.com/algolia/react-instantsearch/issues/2626)) ([6ccad49](https://github.com/algolia/react-instantsearch/commit/6ccad49)) -* **ssr:** avoid duplicate serializing ([#2726](https://github.com/algolia/react-instantsearch/issues/2726)) ([c768b1a](https://github.com/algolia/react-instantsearch/commit/c768b1a)) -* **voiceSearch:** fix incorrect status on stop ([#2535](https://github.com/algolia/react-instantsearch/issues/2535)) ([824dc22](https://github.com/algolia/react-instantsearch/commit/824dc22)) - - -### Code Refactoring - -* **lodash:** get ([#2461](https://github.com/algolia/react-instantsearch/issues/2461)) ([527b879](https://github.com/algolia/react-instantsearch/commit/527b879)) -* **lodash:** has ([#2434](https://github.com/algolia/react-instantsearch/issues/2434)) ([75a4a15](https://github.com/algolia/react-instantsearch/commit/75a4a15)) -* **lodash:** has been fully removed - -### Features - -* **autocomplete:** add queryID & position to provided hits ([#2687](https://github.com/algolia/react-instantsearch/issues/2687)) ([e453dab](https://github.com/algolia/react-instantsearch/commit/e453dab)) -* **client:** remove algoliaClient, appId & apiKey ([#2338](https://github.com/algolia/react-instantsearch/issues/2338)) ([b84a0b5](https://github.com/algolia/react-instantsearch/commit/b84a0b5)) (use searchClient exclusively now) -* **context:** migrate to new React context ([#2178](https://github.com/algolia/react-instantsearch/issues/2178)) ([0a1abea](https://github.com/algolia/react-instantsearch/commit/0a1abea)), closes [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2189](https://github.com/algolia/react-instantsearch/issues/2189) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) [#2179](https://github.com/algolia/react-instantsearch/issues/2179) [#2180](https://github.com/algolia/react-instantsearch/issues/2180) [#2181](https://github.com/algolia/react-instantsearch/issues/2181) [#2185](https://github.com/algolia/react-instantsearch/issues/2185) [#2192](https://github.com/algolia/react-instantsearch/issues/2192) [#2190](https://github.com/algolia/react-instantsearch/issues/2190) -* **ssr:** update the SSR API ([#2555](https://github.com/algolia/react-instantsearch/issues/2555)) ([925bdb8](https://github.com/algolia/react-instantsearch/commit/925bdb8)), closes [#2536](https://github.com/algolia/react-instantsearch/issues/2536) [#2537](https://github.com/algolia/react-instantsearch/issues/2537) - - -### BREAKING CHANGES - -* **searchClient:** argument is the only option now. - -Previously there were three options to pass a search client: searchClient, appId & apiKey, algoliaClient. The latter two have been removed, and now only `searchClient` is accepted. This searchClient is an instance of the `algoliasearch` module: - -```js -import algoliasearch from 'algoliasearch/lite'; - -const searchClient = algoliasearch( - 'myAppId', - 'myApiKey', - { _useRequestCache: true } -); - -// ... - -``` - -If you were relying on duplicate requests not being fired when using appId & apiKey before, you need to enable the `_useRequestCache` option now. - -* **SSR:** imports have changed - -In the server, you now directly import `findResultsState`, which now requires a `searchClient` in the second argument. - -In the App, you now use a regular `InstantSearch` component. - -* **Index & InstantSearch:** Remove `root` DOM element - -These elements now are pure containers for their children, and don't add a `div` to the DOM anymore. If you were relying on those for styling, wrap the `InstantSearch` and `Index` element with a `div` with an appropriate class. - -* **Index & InstantSearch:** Remove support for `root` prop - -Since these two arguments now no longer wrap their children in an element, they no longer accept a `root` prop. - -* **Highlight:** some paths will no longer be accepted - -We only accept paths separated with a dot or bracket now, like before. It's possible that a different type of path worked undocumented, but no longer does. - -* **algoliasearch-helper:** updating to the next major version - -This library is mostly internal, but it has had a major refactor (including removing lodash). This has no impact, unless you are dealing with it using `createConnector`. See the [migration guide](https://github.com/algolia/algoliasearch-helper-js/blob/next/documentation-src/metalsmith/content/upgrade.md) for the v3 of algoliasearch-helper for more information. - -# [5.7.0](https://github.com/algolia/react-instantsearch/compare/v5.6.0...v5.7.0) (2019-06-04) - - -### Bug Fixes - -* **highlight:** allow array as "attribute" ([#2474](https://github.com/algolia/react-instantsearch/issues/2474)) ([9dc829a](https://github.com/algolia/react-instantsearch/commit/9dc829a)), closes [#2461](https://github.com/algolia/react-instantsearch/issues/2461) -* **indexUtils:** allow index with dots in it ([#2350](https://github.com/algolia/react-instantsearch/issues/2350)) ([f91906f](https://github.com/algolia/react-instantsearch/commit/f91906f)) - - -### Features - -* **voiceSearch:** add voice search widget ([#2316](https://github.com/algolia/react-instantsearch/issues/2316)) ([0e3b124](https://github.com/algolia/react-instantsearch/commit/0e3b124)) - - - -# [5.6.0](https://github.com/algolia/react-instantsearch/compare/v5.5.0...v5.6.0) (2019-05-15) - - -### Bug Fixes - -* **connectQueryRules:** avoid to throw an error with undefined values ([#2436](https://github.com/algolia/react-instantsearch/issues/2436)) ([1e18287](https://github.com/algolia/react-instantsearch/commit/1e18287)) - - -### Features - -* **infiniteHits:** add previous button ([#2296](https://github.com/algolia/react-instantsearch/issues/2296)) ([010a69a](https://github.com/algolia/react-instantsearch/commit/010a69a)) - - - -# [5.5.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0...v5.5.0) (2019-04-23) - - -### Bug Fixes - -* **createInstantSearch:** change the User-Agent to use the new specs ([#2209](https://github.com/algolia/react-instantsearch/issues/2209)) ([642ba0b](https://github.com/algolia/react-instantsearch/commit/642ba0b)) - - -### Features - -* **DOMMaps:** expose withGoogleMaps HOC [PART-1] ([#2000](https://github.com/algolia/react-instantsearch/issues/2000)) ([2ae1dea](https://github.com/algolia/react-instantsearch/commit/2ae1dea)) -* **queryRules:** add Query Rules features ([#2286](https://github.com/algolia/react-instantsearch/issues/2286)) ([3ae9c01](https://github.com/algolia/react-instantsearch/commit/3ae9c01)) -* **insights:** add insights features ([#2215](https://github.com/algolia/react-instantsearch/pull/2215)) ([961e7a7](https://github.com/algolia/react-instantsearch/commit/961e7a7)) - - - -# [5.4.0](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.1...v5.4.0) (2019-02-05) - - -### Bug Fixes - -* **DOMMaps:** set React & React DOM as peer deps ([#1922](https://github.com/algolia/react-instantsearch/issues/1922)) ([2f2cefd](https://github.com/algolia/react-instantsearch/commit/2f2cefd)) - - - -# [5.4.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.4.0-beta.0...v5.4.0-beta.1) (2019-01-10) - - -### Bug Fixes - -* **deps:** sync algoliasearch version ([#1879](https://github.com/algolia/react-instantsearch/issues/1879)) ([40f9c26](https://github.com/algolia/react-instantsearch/commit/40f9c26)) -* **maps:** use stable version for peer deps ([#1887](https://github.com/algolia/react-instantsearch/issues/1887)) ([9055167](https://github.com/algolia/react-instantsearch/commit/9055167)) - - - -# [5.4.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.3.2...v5.4.0-beta.0) (2019-01-08) - - -### Features - -* **Index:** introduce `indexId` prop ([#1833](https://github.com/algolia/react-instantsearch/issues/1833)) ([ec9e0fb](https://github.com/algolia/react-instantsearch/commit/ec9e0fb)) - - - - -## [5.3.2](https://github.com/algolia/react-instantsearch/compare/v5.3.1...v5.3.2) (2018-10-30) - - -### Bug Fixes - -* **sffv:** clamp maxFacetHits to the allowed range ([#1696](https://github.com/algolia/react-instantsearch/issues/1696)) ([83ce245](https://github.com/algolia/react-instantsearch/commit/83ce245)) - - - - -## [5.3.1](https://github.com/algolia/react-instantsearch/compare/v5.3.0...v5.3.1) (2018-09-26) - - -### Bug Fixes - -* **connector:** ensure canRefine is computed on the transformed items ([#1568](https://github.com/algolia/react-instantsearch/pull/1568)) ([c95384f](https://github.com/algolia/react-instantsearch/commit/c95384f)) -* **toggle:** ensure facet is present ([#1613](https://github.com/algolia/react-instantsearch/issues/1613)) ([e914ff6](https://github.com/algolia/react-instantsearch/commit/e914ff6)) - - - - -# [5.3.0](https://github.com/algolia/react-instantsearch/compare/v5.2.3...v5.3.0) (2018-09-24) - - -### Bug Fixes - -* **SSR:** bind getSearchParmaters to the component instance ([f34cb3d](https://github.com/algolia/react-instantsearch/commit/f34cb3d)) -* **GoogleMapsLoader:** pick google maps version ([#1540](https://github.com/algolia/react-instantsearch/issues/1540)) ([b14efcf](https://github.com/algolia/react-instantsearch/commit/b14efcf)) - - -### Features - -* **connectToggleRefinement:** implement canRefine & count ([#1588](https://github.com/algolia/react-instantsearch/issues/1588)) ([40672dd](https://github.com/algolia/react-instantsearch/commit/40672dd)) - - - - -## [5.2.3](https://github.com/algolia/react-instantsearch/compare/v5.2.2...v5.2.3) (2018-08-16) - - -### Bug Fixes - -* Allow object as type for Root (closes [#1446](https://github.com/algolia/react-instantsearch/issues/1446)) ([#1461](https://github.com/algolia/react-instantsearch/issues/1461)) ([7c2317b](https://github.com/algolia/react-instantsearch/commit/7c2317b)) -* **List:** render children list only when required ([#1472](https://github.com/algolia/react-instantsearch/issues/1472)) ([9eb2cbb](https://github.com/algolia/react-instantsearch/commit/9eb2cbb)), closes [#1459](https://github.com/algolia/react-instantsearch/issues/1459) - - - - -## [5.2.2](https://github.com/algolia/react-instantsearch/compare/v5.2.1...v5.2.2) (2018-07-16) - - -Publish the previous version on `stable`. - - - - -## [5.2.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0...v5.2.1) (2018-07-16) - - -### Bug Fixes - -* **GoogleMapsLoader:** inline the import to scriptjs ([#1427](https://github.com/algolia/react-instantsearch/issues/1427)) ([8019416](https://github.com/algolia/react-instantsearch/commit/8019416)) - - - - -# [5.2.0](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.2...v5.2.0) (2018-07-04) - - -### Bug Fixes - -* **translatable:** avoid create a new function on every render ([#1383](https://github.com/algolia/react-instantsearch/issues/1383)) ([1285b3b](https://github.com/algolia/react-instantsearch/commit/1285b3b)) - - -### Features - -* **core:** export translatable ([#1351](https://github.com/algolia/react-instantsearch/issues/1351)) ([6d5a89d](https://github.com/algolia/react-instantsearch/commit/6d5a89d)) -* **maps:** add connector & widget ([#1171](https://github.com/algolia/react-instantsearch/issues/1171)) ([16e288a](https://github.com/algolia/react-instantsearch/commit/16e288a)) - - - - -# [5.2.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.1...v5.2.0-beta.2) (2018-06-19) - - -### Features - -* export highlight tags from DOM / native ([#1342](https://github.com/algolia/react-instantsearch/issues/1342)) ([28a699e](https://github.com/algolia/react-instantsearch/commit/28a699e)) -* **createInstantSearch:** enable _useRequestCache ([#1346](https://github.com/algolia/react-instantsearch/issues/1346)) ([f772600](https://github.com/algolia/react-instantsearch/commit/f772600)) -* **dom:** export create class name ([#1348](https://github.com/algolia/react-instantsearch/issues/1348)) ([9017468](https://github.com/algolia/react-instantsearch/commit/9017468)) - - - - -# [5.2.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.2.0-beta.0...v5.2.0-beta.1) (2018-06-04) - - -### Bug Fixes - -* **dom:** publish server file ([#1305](https://github.com/algolia/react-instantsearch/issues/1305)) ([bd79693](https://github.com/algolia/react-instantsearch/commit/bd79693)) - - - - -# [5.2.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v5.1.0...v5.2.0-beta.0) (2018-06-04) - - -This new version introduce a complete revamp of the package structure, but it should be completely transparent for the users. - -If you have any troubles with this version please open a issue on [Github](https://github.com/algolia/react-instantsearch/issues/new), thanks! - - - - -# [5.1.0](https://github.com/algolia/react-instantsearch/compare/v5.0.3...v5.1.0) (2018-05-28) - - -### Bug Fixes - -* **connectInfiniteHits:** always set a value for previous page ([#1195](https://github.com/algolia/react-instantsearch/issues/1195)) ([4c218d5](https://github.com/algolia/react-instantsearch/commit/4c218d5)) -* **indexUtils:** avoid throw an error on cleanUp multi indices ([#1265](https://github.com/algolia/react-instantsearch/issues/1265)) ([12f5ace](https://github.com/algolia/react-instantsearch/commit/12f5ace)) - - -### Features - -* **searchClient:** Add support for custom Search Clients ([#1216](https://github.com/algolia/react-instantsearch/issues/1216)) ([174cc28](https://github.com/algolia/react-instantsearch/commit/174cc28)) - - - - -## [5.0.3](https://github.com/algolia/react-instantsearch/compare/v5.0.2...v5.0.3) (2018-04-03) - - -### Bug Fixes - -* revert dependencies as devDependencies ([#1135](https://github.com/algolia/react-instantsearch/issues/1135)) ([6b627bb](https://github.com/algolia/react-instantsearch/commit/6b627bb)) - - - - -## [5.0.2](https://github.com/algolia/react-instantsearch/compare/v5.0.1...v5.0.2) (2018-04-03) - - -### Bug Fixes - -* use lodash version of unsupported Array.{fill, find} ([#1118](https://github.com/algolia/react-instantsearch/issues/1118)) ([ea7bf42](https://github.com/algolia/react-instantsearch/commit/ea7bf42)) - - - - -## [5.0.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0...v5.0.1) (2018-03-12) - - -### Bug Fixes - -* **connectInfiniteHits:** always provide an array for hits ([#1064](https://github.com/algolia/react-instantsearch/issues/1064)) ([c75e38b](https://github.com/algolia/react-instantsearch/commit/c75e38b)) - - - - -# [5.0.0](https://github.com/algolia/react-instantsearch/compare/v4.5.2...v5.0.0) (2018-03-06) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.5.2](https://github.com/algolia/react-instantsearch/compare/v4.5.1...v4.5.2) (2018-03-06) - - -### Bug Fixes - -* **connectRange:** update default refinement propTypes ([#978](https://github.com/algolia/react-instantsearch/issues/978)) ([c065fb1](https://github.com/algolia/react-instantsearch/commit/c065fb1)) -* **IndexUtils:** avoid throw an error when cleanUp multi index ([#1019](https://github.com/algolia/react-instantsearch/issues/1019)) ([865a3c3](https://github.com/algolia/react-instantsearch/commit/865a3c3)) -* **SearchBox:** avoid to bind click on reset button ([#979](https://github.com/algolia/react-instantsearch/issues/979)) ([ea3063a](https://github.com/algolia/react-instantsearch/commit/ea3063a)) - - - - -# [5.0.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v5.0.0-beta.0...v5.0.0-beta.1) (2018-02-06) - - -Apply features & bug fixes from [v4.5.0](#450-2018-02-06) & [v4.5.1](#451-2018-02-06) on the v5. - -See their CHANGELOG for more details. - - - - -## [4.5.1](https://github.com/algolia/react-instantsearch/compare/v4.5.0...v4.5.1) (2018-02-06) - - -### Bug Fixes - -* **StarRating:** move to 1 based instead of 0 ([#949](https://github.com/algolia/react-instantsearch/issues/949)) ([eb0152d](https://github.com/algolia/react-instantsearch/commit/eb0152d)) - - - - -# [4.5.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v4.5.0) (2018-02-06) - - -### Bug Fixes - -* **connectRange:** use the same behaviour for currentRefinement in getMetadata ([#923](https://github.com/algolia/react-instantsearch/issues/923)) ([08917b6](https://github.com/algolia/react-instantsearch/commit/08917b6)) -* **connectToggle:** use currentRefinement in metadata instead of the label ([#909](https://github.com/algolia/react-instantsearch/issues/909)) ([89cae2b](https://github.com/algolia/react-instantsearch/commit/89cae2b)) -* **StarRatings:** always show the stars below ([#929](https://github.com/algolia/react-instantsearch/issues/929)) ([22bf93a](https://github.com/algolia/react-instantsearch/commit/22bf93a)) - - -### Features - -* **connectStateResults:** expose isSearchStalled ([#933](https://github.com/algolia/react-instantsearch/issues/933)) ([f45ba27](https://github.com/algolia/react-instantsearch/commit/f45ba27)) - - - -# [5.0.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.4.2...v5.0.0-beta.0) (2018-01-30) - - -This new version introduce a complete revamp of the naming and the HTML output of most widgets. The goal of this release is to provide improved semantics to our users. - -This release also introduces a new CSS naming convention which will be reused across all InstantSearch libraries. This will enable the possibility to develop cross-libraries CSS themes easily. - -You can find all the informations for the migration [in our documentation](https://www.algolia.com/doc/guides/building-search-ui/upgrade-guides/react/#upgrade-from-v4-to-v5). - - - - -## [4.4.2](https://github.com/algolia/react-instantsearch/compare/v4.4.1...v4.4.2) (2018-01-24) - - -### Bug Fixes - -* **currentRefinements:** give access to id and index from transformItems for deduplication ([#830](https://github.com/algolia/react-instantsearch/issues/830)) ([316b8f5](https://github.com/algolia/react-instantsearch/commit/316b8f5)) -* pass maxFacetHits to SFFV ([#863](https://github.com/algolia/react-instantsearch/issues/863)) ([de23a46](https://github.com/algolia/react-instantsearch/commit/de23a46)) - - - - -## [4.4.1](https://github.com/algolia/react-instantsearch/compare/v4.4.0...v4.4.1) (2018-01-09) - - -### Bug Fixes - -* **SearchBox**: clear SearchBox without search as you type ([#802](https://github.com/algolia/react-instantsearch/issues/802)) ([c49b2b6](https://github.com/algolia/react-instantsearch/commit/c49b2b6)) -* **connectRange:** check if facet exist before access ([#797](https://github.com/algolia/react-instantsearch/issues/797)) ([6520760](https://github.com/algolia/react-instantsearch/commit/6520760)) -* **stories:** avoid to use linear-background it breaks Argos every time ([#804](https://github.com/algolia/react-instantsearch/issues/804)) ([0beded7](https://github.com/algolia/react-instantsearch/commit/0beded7)) -* **stories:** limit hits per page on Index ([#806](https://github.com/algolia/react-instantsearch/issues/806)) ([6eb14d3](https://github.com/algolia/react-instantsearch/commit/6eb14d3)) - - -### Features - -* **Index:** allow custom root ([#792](https://github.com/algolia/react-instantsearch/issues/792)) ([d793b0a](https://github.com/algolia/react-instantsearch/commit/d793b0a)) - - - - -# [4.4.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0...v4.4.0) (2018-01-03) - - -### Bug Fixes - -* **createInstantSearch:** remove the client from the Snapshot ([#749](https://github.com/algolia/react-instantsearch/issues/749)) ([700d8f4](https://github.com/algolia/react-instantsearch/commit/700d8f4)) -* refresh cache memory leak example ([#784](https://github.com/algolia/react-instantsearch/issues/784)) ([cf228ac](https://github.com/algolia/react-instantsearch/commit/cf228ac)) -* **stories:** rename InstantSearch to `` ([#789](https://github.com/algolia/react-instantsearch/issues/789)) ([05efda5](https://github.com/algolia/react-instantsearch/commit/05efda5)) - - -### Features - -* InstantSearch root props ([#770](https://github.com/algolia/react-instantsearch/issues/770)) ([2d458f8](https://github.com/algolia/react-instantsearch/commit/2d458f8)) - - - - -# [4.3.0](https://github.com/algolia/react-instantsearch/compare/v4.3.0-beta.0...v4.3.0) (2017-12-20) - - -### Bug Fixes - -* reset page with multi index ([#665](https://github.com/algolia/react-instantsearch/issues/665)) ([865b7dc](https://github.com/algolia/react-instantsearch/commit/865b7dc)) -* track all index in the manager ([#660](https://github.com/algolia/react-instantsearch/issues/660)) ([793502b](https://github.com/algolia/react-instantsearch/commit/793502b)) - - -### Features - -* **SearchBox:** provide a loading indicator ([#544](https://github.com/algolia/react-instantsearch/issues/544)) ([189659e](https://github.com/algolia/react-instantsearch/commit/189659e)) -* **Highlight:** support array of strings ([#715](https://github.com/algolia/react-instantsearch/issues/715)) ([8e93c6a](https://github.com/algolia/react-instantsearch/commit/8e93c6a)) - - - - -# [4.3.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.2.0...v4.3.0-beta.0) (2017-11-27) - - -### Bug Fixes - -* **babelrc:** add a key for each env development, production, es ([#547](https://github.com/algolia/react-instantsearch/issues/547)) ([fa9528d](https://github.com/algolia/react-instantsearch/commit/fa9528d)) -* **localizecount:** allow localized string for count in MenuSelect ([#657](https://github.com/algolia/react-instantsearch/issues/657)) ([67ebd34](https://github.com/algolia/react-instantsearch/commit/67ebd34)) -* **react-router-example:** Properly update search query when using browser navigation ([#604](https://github.com/algolia/react-instantsearch/issues/604)) ([9ee6600](https://github.com/algolia/react-instantsearch/commit/9ee6600)) - - -### Features - -* **refreshcache:** add prop refresh to InstantSearch instance ([#619](https://github.com/algolia/react-instantsearch/issues/619)) ([19f6de0](https://github.com/algolia/react-instantsearch/commit/19f6de0)) - - - - -# [4.2.0](https://github.com/algolia/react-instantsearch/compare/v4.1.3...v4.2.0) (2017-11-02) - - -### Bug Fixes - -* **connectRange:** handle boundaries on first call ([9f14dc0](https://github.com/algolia/react-instantsearch/commit/9f14dc0)) -* **connectRange:** use refine instead of cleanUp in metadata ([#526](https://github.com/algolia/react-instantsearch/issues/526)) ([1861235](https://github.com/algolia/react-instantsearch/commit/1861235)) -* **hierarchicaMenu:** allow sorting and using limit ([fe178ed](https://github.com/algolia/react-instantsearch/commit/fe178ed)), closes [#92](https://github.com/algolia/react-instantsearch/issues/92) -* **InfiniteHits:** add disabled style to the LoadMore button ([#477](https://github.com/algolia/react-instantsearch/issues/477)) ([faba1ad](https://github.com/algolia/react-instantsearch/commit/faba1ad)) -* **Range:** handle float, allow reset and respect boundaries ([75969b8](https://github.com/algolia/react-instantsearch/commit/75969b8)) -* **RangeInput:** fix compatibility with React 16 & Panel ([3f218db](https://github.com/algolia/react-instantsearch/commit/3f218db)) -* **searchbox:** add maxlength 512 ([#542](https://github.com/algolia/react-instantsearch/issues/542)) ([5bd4033](https://github.com/algolia/react-instantsearch/commit/5bd4033)), closes [#510](https://github.com/algolia/react-instantsearch/issues/510) - - -### Features - -* **MenuSelect:** add component and connector ([cc6e0d7](https://github.com/algolia/react-instantsearch/commit/cc6e0d7)) - - - - -## [4.1.3](https://github.com/algolia/react-instantsearch/compare/v4.1.2...v4.1.3) (2017-10-09) - - -### Bug Fixes - -* **List:** remove React16 warning ([#442](https://github.com/algolia/react-instantsearch/issues/442)) ([8d6cf18](https://github.com/algolia/react-instantsearch/commit/8d6cf18)) - - -### Features - -* **connectStateResults:** add component props ([#434](https://github.com/algolia/react-instantsearch/issues/434)) ([c629b97](https://github.com/algolia/react-instantsearch/commit/c629b97)) - - - - -## [4.1.2](https://github.com/algolia/react-instantsearch/compare/v4.1.1...v4.1.2) (2017-09-26) - - -### Features - -* **Conditional:** add connectStateResults connector ([#357](https://github.com/algolia/react-instantsearch/issues/357)) ([462df5f](https://github.com/algolia/react-instantsearch/commit/462df5f)) - - - - -## [4.1.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0...v4.1.1) (2017-09-13) - - -### Bug Fixes - -* **MultiIndex:** reset page to 1 when share widgets refine (#312) ([c85a7bf](https://github.com/algolia/react-instantsearch/commit/c85a7bf)) -* **MultiIndex:** Trigger new search when `` props are updated (#318) ([bb11965](https://github.com/algolia/react-instantsearch/commit/bb11965)) - - - - -# [4.1.0](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.5...v4.1.0) (2017-08-28) - - -### Bug Fixes - -* **Highlighting:** revert breaking change (#245) ([045ee06](https://github.com/algolia/react-instantsearch/commit/045ee06)) -* **List:** adds support for any type of renderable element (#266) ([d848bb6](https://github.com/algolia/react-instantsearch/commit/d848bb6)) -* **Pagination:** fixed the offset ([3c0fff2](https://github.com/algolia/react-instantsearch/commit/3c0fff2)) -* **PoweredBy:** aria-* tags are not camelcased (#261) ([dc4a5bb](https://github.com/algolia/react-instantsearch/commit/dc4a5bb)) - - - - -# [4.1.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.4...v4.1.0-beta.5) (2017-08-08) - - -### Bug Fixes - -* **SSR:** clean SP before rendering agan (#238) ([e765886](https://github.com/algolia/react-instantsearch/commit/e765886)) - - -### Features - -* **Breadcrumb:** add a new widget & connector (#228) ([7f8f3ae](https://github.com/algolia/react-instantsearch/commit/7f8f3ae)) - - - - -# [4.1.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.3...v4.1.0-beta.4) (2017-08-03) - - -### Bug Fixes - -* **deps:** Update dependency lint-staged to version ^4.0.0 (#201) ([6867a1b](https://github.com/algolia/react-instantsearch/commit/6867a1b)) -* **nextjs/ssr:** parse `params.asPath` (#189) ([ae17da0](https://github.com/algolia/react-instantsearch/commit/ae17da0)) -* **PoweredBy:** add a label to the Algolia logo (#216) ([cd235bd](https://github.com/algolia/react-instantsearch/commit/cd235bd)) -* **react:** remove typo around `"" 2` (#220) ([f73eb04](https://github.com/algolia/react-instantsearch/commit/f73eb04)) -* **ScrollTo:** scroll to only if change triggered by the widget observed (#202) ([2d76022](https://github.com/algolia/react-instantsearch/commit/2d76022)) -* **theme:** format the count of items appearing in a refinement (#217) ([2225c24](https://github.com/algolia/react-instantsearch/commit/2225c24)) - - - - -# [4.1.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.2...v4.1.0-beta.3) (2017-07-25) - - -### Bug Fixes - -* **error:** reset error when receiving results of a query (not when sending it) (#179) ([bb12c29](https://github.com/algolia/react-instantsearch/commit/bb12c29)) -* **highlight:** wrong parsing between client and server (#183) ([2daae70](https://github.com/algolia/react-instantsearch/commit/2daae70)) -* **poweredBy:** SSR compatibility (#181) ([ec0fa8a](https://github.com/algolia/react-instantsearch/commit/ec0fa8a)) - - -### BREAKING CHANGES - -* **highlight:** We remove the timestamp present in our highlight preTag and postTag. If you were using regex to parse the -highlighting results then you'll need to adapt it as now it's only "ais-highlight". - - - - -# [4.1.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.1...v4.1.0-beta.2) (2017-07-20) - - -### Bug Fixes - -* **error:** reset error if next query is successful (#175) ([ff50a07](https://github.com/algolia/react-instantsearch/commit/ff50a07)) - - - - -# [4.1.0-beta.1](https://github.com/algolia/react-instantsearch/compare/v4.1.0-beta.0...v4.1.0-beta.1) (2017-07-12) - - - - -# [4.1.0-beta.0](https://github.com/algolia/react-instantsearch/compare/v4.0.7...v4.1.0-beta.0) (2017-07-10) - - -### Bug Fixes - -* **argos:** address flakyness (#152) ([84ef8f1](https://github.com/algolia/react-instantsearch/commit/84ef8f1)) - - -### Features - -* **server-side rendering:** Add API features for server-side rendering ([86b14d1](https://github.com/algolia/react-instantsearch/commit/86b14d1)) - - - - -## [4.0.7](https://github.com/algolia/react-instantsearch/compare/v4.0.6...v4.0.7) (2017-07-06) - - -### Bug Fixes - -* **results:** revert commit that ensure hits are returned only if right indices (#149) ([df9aa25](https://github.com/algolia/react-instantsearch/commit/df9aa25)) - - - - -## [4.0.6](https://github.com/algolia/react-instantsearch/compare/v4.0.5...v4.0.6) (2017-06-29) - - -### Bug Fixes - -* **store:** delay call to listener to prevent infinite loops (#143) ([0945958](https://github.com/algolia/react-instantsearch/commit/0945958)) - - - - -## [4.0.5](https://github.com/algolia/react-instantsearch/compare/v4.0.4...v4.0.5) (2017-06-26) - - -### Bug Fixes - -* **MultiIndex:** ensure getResults return only hits matching index in the context (#136) ([124ffe6](https://github.com/algolia/react-instantsearch/commit/124ffe6)) -* **MultiIndex:** handle if namespace isn't in search state (#139) ([1aab324](https://github.com/algolia/react-instantsearch/commit/1aab324)) -* **storybook:** process CSS through autoprefixer (#138) ([62cf512](https://github.com/algolia/react-instantsearch/commit/62cf512)) - - - - -## [4.0.4](https://github.com/algolia/react-instantsearch/compare/v4.0.3...v4.0.4) (2017-06-19) - - -### Bug Fixes - -* **MultiIndex:** handle switch between mono and multi index (#132) ([e161921](https://github.com/algolia/react-instantsearch/commit/e161921)) - - - - -## [4.0.3](https://github.com/algolia/react-instantsearch/compare/v4.0.2...v4.0.3) (2017-06-14) - - -### Bug Fixes - -* **SFFV:** search status we're not inside search state (#125) ([5f3e670](https://github.com/algolia/react-instantsearch/commit/5f3e670)) - - - - -## [4.0.2](https://github.com/algolia/react-instantsearch/compare/v4.0.1...v4.0.2) (2017-05-30) - - - - -## [4.0.1](https://github.com/algolia/react-instantsearch/compare/v4.0.0...v4.0.1) (2017-05-17) - - -### Bug Fixes - -* **state:** nested attributes for faceting were not handled ([11bd122](https://github.com/algolia/react-instantsearch/commit/11bd122)) - - - - -# [4.0.0](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.6...v4.0.0) (2017-05-15) - -### Features and migration guide - -You can find all the details of the release and the migration guide from v3 to v4 here: https://discourse.algolia.com/t/react-instantsearch-v4/1329. - - - -# [4.0.0-beta.6](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.5...v4.0.0-beta.6) (2017-05-04) - - - - -# [4.0.0-beta.5](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.4...v4.0.0-beta.5) (2017-05-02) - - -### Bug Fixes - -* **connectAutoComplete:** allow usage with hits from a single index (#75) ([8b3b358](https://github.com/algolia/react-instantsearch/commit/8b3b358)), closes [#74](https://github.com/algolia/react-instantsearch/issues/74) -* **InstantSearch:** update algoliaClient when it change (#70) ([9e97dbd](https://github.com/algolia/react-instantsearch/commit/9e97dbd)) - - - - -# [4.0.0-beta.4](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.3...v4.0.0-beta.4) (2017-04-25) - - -### Bug Fixes - -* **MultIndex:** no need to nest hits, if those are from main index. (#56) ([86e0bd7](https://github.com/algolia/react-instantsearch/commit/86e0bd7)) - - -### Features - -* **MultiIndex:** remove the need for virtual hits when using connectAutoComplete (#45) ([7549019](https://github.com/algolia/react-instantsearch/commit/7549019)) - - - - -# [4.0.0-beta.3](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.2...v4.0.0-beta.3) (2017-04-21) - - -### Bug Fixes - -* replace usage of Object.values (#47) ([4c79e3e](https://github.com/algolia/react-instantsearch/commit/4c79e3e)) - - - - -# [4.0.0-beta.2](https://github.com/algolia/react-instantsearch/compare/v4.0.0-beta.1...v4.0.0-beta.2) (2017-04-18) - - -### Bug Fixes - -* **InstantSearch:** dont fire request/onsearchStateChange when unmounting (#26) ([9a1487a](https://github.com/algolia/react-instantsearch/commit/9a1487a)) -* **MultiIndex:** derived helper were using main index specifics params (#36) ([991fea6](https://github.com/algolia/react-instantsearch/commit/991fea6)) -* **MultiIndex:** revert breaking change if no multiple index (#32) ([44f7de0](https://github.com/algolia/react-instantsearch/commit/44f7de0)) -* **util:** remove empty key was removing non object key (#29) ([9f795c7](https://github.com/algolia/react-instantsearch/commit/9f795c7)) - - -### Features - -* **Highlighter:** allow rendering to custom tag (#11) ([52a1212](https://github.com/algolia/react-instantsearch/commit/52a1212)) -* **SearchBox:** add default width and height to buttons. (#34) ([bcabf9b](https://github.com/algolia/react-instantsearch/commit/bcabf9b)) - - - - -# [4.0.0-beta.1](https://github.com/algolia/instantsearch.js/compare/v4.0.0-beta.0...v4.0.0-beta.1) (2017-04-03) - - -### Bug Fixes - -* **SFFV:** fix wrong query behaviour with slow network (#2086) ([c251e8f](https://github.com/algolia/instantsearch.js/commit/c251e8f)), closes [#2086](https://github.com/algolia/instantsearch.js/issues/2086) - - - - -# [4.0.0-beta.0](https://github.com/algolia/instantsearch.js/compare/v3.3.0...v4.0.0-beta.0) (2017-03-28) - - -### Features - -* **multi-index:** ease multi index and auto complete ([09a4e1d](https://github.com/algolia/instantsearch.js/commit/09a4e1d)) - - -### BREAKING CHANGES - -* multi-index: * Reseting the pagination should be done at each connector level inside the "refine" function when returning the search state. -* The current page now appears inside the search state when a widget is used -* Query values are part of the items prop of the connectCurrentRefinements connector. Behaviour is unchanged, query will be filtered if clearsQuery prop is false. -* Add the index name to all the current refinements items. (not used by our widgets yet, but available if needed). - - - - -# [3.3.0](https://github.com/algolia/instantsearch.js/compare/v3.2.2-beta0...v3.3.0) (2017-03-22) - - -### Bug Fixes - -* **example:** Fix access to props in react-router example ([1417d6f](https://github.com/algolia/instantsearch.js/commit/1417d6f)) - - - - -## [3.2.2-beta0](https://github.com/algolia/instantsearch.js/compare/v3.2.1...v3.2.2-beta0) (2017-03-20) - - -### Bug Fixes - -* **InfiniteHits:** provide translation key for `Load More` (#2048) ([6130bf2](https://github.com/algolia/instantsearch.js/commit/6130bf2)) -* **SearchBox:** better mobile behaviour by default ([ea968b3](https://github.com/algolia/instantsearch.js/commit/ea968b3)) -* **example:** link to instantsearch/react (#2007) ([5e674cd](https://github.com/algolia/instantsearch.js/commit/5e674cd)) -* **recipes:** react router v4 ([de673bf](https://github.com/algolia/instantsearch.js/commit/de673bf)) - - -### Features - -* **SearchBox:** add role=search to the form (#2046) ([d1e90f3](https://github.com/algolia/instantsearch.js/commit/d1e90f3)) -* **SearchBox:** allow custom reset and submit components (#1991) ([cd303d7](https://github.com/algolia/instantsearch.js/commit/cd303d7)) -* **searchBox:** add event handling ([e267ab6](https://github.com/algolia/instantsearch.js/commit/e267ab6)), closes [#2017](https://github.com/algolia/instantsearch.js/issues/2017) - - - - -## [3.2.1](https://github.com/algolia/instantsearch.js/compare/v3.2.0...v3.2.1) (2017-02-22) - - -### Bug Fixes - -* **umd:** Add connectors to UMD build (#1988) ([23ac5e6](https://github.com/algolia/instantsearch.js/commit/23ac5e6)), closes [#1987](https://github.com/algolia/instantsearch.js/issues/1987) - - - - -# [3.2.0](https://github.com/algolia/instantsearch.js/compare/v3.1.0...v3.2.0) (2017-02-15) - - -### Bug Fixes - -* **Configure:** use props a unique source of truth (#1967) ([9d53d86](https://github.com/algolia/instantsearch.js/commit/9d53d86)) -* **SearchBox:** Safari can only have with xlinkHref (#1970) ([7ab00bd](https://github.com/algolia/instantsearch.js/commit/7ab00bd)), closes [#1968](https://github.com/algolia/instantsearch.js/issues/1968) - - -### Features - -* **MultiRange:** add an all range (#1959) ([a3dc950](https://github.com/algolia/instantsearch.js/commit/a3dc950)) - - -### BREAKING CHANGES - -* MultiRange: - MultiRange/connectMultiRange: will add a "All" range to allow unselection of range without the usage of CurrentRefinements. This range can be either filtered or ramove via CSS if not needed. The label can be changed by using our translations system. - - - - -# [3.1.0](https://github.com/algolia/instantsearch.js/compare/v3.0.0...v3.1.0) (2017-02-08) - - -### Bug Fixes - -* **Configure:** call onSearchStateChange when props are updated (#1953) ([7e151db](https://github.com/algolia/instantsearch.js/commit/7e151db)), closes [#1950](https://github.com/algolia/instantsearch.js/issues/1950) -* **Configure:** trigger onSearchStateChange with the right data ([11e5af8](https://github.com/algolia/instantsearch.js/commit/11e5af8)) -* **createConnector:** updates with latest props on state change (#1951) ([cd3a82c](https://github.com/algolia/instantsearch.js/commit/cd3a82c)) - - -### Features - -* **ClearAll:** add withQuery to also clear the search query (#1958) ([c0e695b](https://github.com/algolia/instantsearch.js/commit/c0e695b)) - - - - -# [3.0.0](https://github.com/algolia/instantsearch.js/compare/v2.2.5...v3.0.0) (2017-02-06) - - -### Bug Fixes - -* ***List:** disable shortcuts in *List SearchBoxes (#1921) ([51a76ae](https://github.com/algolia/instantsearch.js/commit/51a76ae)), closes [#1920](https://github.com/algolia/instantsearch.js/issues/1920) -* **Configure:** add configure parameters in search state (#1935) ([0971330](https://github.com/algolia/instantsearch.js/commit/0971330)), closes [#1863](https://github.com/algolia/instantsearch.js/issues/1863) -* **Hits:** limit the hitComponent to be only a function (#1912) ([b3c9578](https://github.com/algolia/instantsearch.js/commit/b3c9578)) -* **Pagination:** fix and indicate when pagination is disabled ([5f20199](https://github.com/algolia/instantsearch.js/commit/5f20199)), closes [#1938](https://github.com/algolia/instantsearch.js/issues/1938) -* **StarRating:** usage with filters (#1933) ([667e9d5](https://github.com/algolia/instantsearch.js/commit/667e9d5)) -* **withSearchBox:** keep displaying searchBox when no items found (#1930) ([30de4cd](https://github.com/algolia/instantsearch.js/commit/30de4cd)) - - -### Features - -* **MultiRange:** indicate if a range has no refinements (#1926) ([80b6450](https://github.com/algolia/instantsearch.js/commit/80b6450)) -* **panel:** add a panel widget (#1889) ([594e1a1](https://github.com/algolia/instantsearch.js/commit/594e1a1)) -* **starRating:** indicate when any refinement has no effect ([c547ae5](https://github.com/algolia/instantsearch.js/commit/c547ae5)) -* **widgets:** default design for disabled states (#1929) ([31f010b](https://github.com/algolia/instantsearch.js/commit/31f010b)) - -### Migration guide - -The migration to V3.0.0 should be safe and you should do it. - -There are two breaking changes that you will need to handle in your codebase: -- Anytime you are using a connector, when there are no more items in it or no more hits, we will still call your Component. Thus you will have to handle cases like dealing with empty arrays and decide if you want to unmount or hide the widget. -- Anytime you are using a widget, when there are no more items in it or no more hits, we will still display the widget. You can then decide to hide it with CSS. - - -## [2.2.5](https://github.com/algolia/instantsearch.js/compare/v2.2.4...v2.2.5) (2017-01-23) - - -### Bug Fixes - -* **currentRefinements:** make removing a toggle refinement work ([8995e64](https://github.com/algolia/instantsearch.js/commit/8995e64)) - - - - -## [2.2.4](https://github.com/algolia/instantsearch.js/compare/v2.2.3...v2.2.4) (2017-01-20) - - -### Bug Fixes - -* **publish:** publish react-instantsearch/dist instead of root (#1884) ([64414e0](https://github.com/algolia/instantsearch.js/commit/64414e0)) - - - - -## [2.2.3](https://github.com/algolia/instantsearch.js/compare/v2.2.2...v2.2.3) (2017-01-20) - - -### Bug Fixes - -* **SFFV:** translations for searchbox were not applied (#1879) ([e9b4ee1](https://github.com/algolia/instantsearch.js/commit/e9b4ee1)) - - - - -## [2.2.2](https://github.com/algolia/instantsearch.js/compare/v2.2.1...v2.2.2) (2017-01-18) - - -### Bug Fixes - -* **react-router:** search was triggered two many times (#1840) ([25e9db5](https://github.com/algolia/instantsearch.js/commit/25e9db5)) -* **SFFV:** empty query triggered a new SFFV (#1875) ([6c8259a](https://github.com/algolia/instantsearch.js/commit/6c8259a)) - - - - -## [2.2.1](https://github.com/algolia/instantsearch.js/compare/v2.2.0...v2.2.1) (2017-01-18) - - -### Bug Fixes - -* **createInstantsearch:** fix missing props (#1867) ([8d319b5](https://github.com/algolia/instantsearch.js/commit/8d319b5)), closes [#1867](https://github.com/algolia/instantsearch.js/issues/1867) - - - - -# [2.2.0](https://github.com/algolia/instantsearch.js/compare/v2.1.0...v2.2.0) (2017-01-17) - - -### Bug Fixes - -* **clear:** clearing wasn't working with too+ same type facets selected (#1820) ([a9a2364](https://github.com/algolia/instantsearch.js/commit/a9a2364)) -* **connectSearchBox:** handle `defaultRefinement` (#1829) ([7a730e2](https://github.com/algolia/instantsearch.js/commit/7a730e2)), closes [#1826](https://github.com/algolia/instantsearch.js/issues/1826) -* **Instantsearch:** Update all props on InstantSearch (#1828) ([2ed9b49](https://github.com/algolia/instantsearch.js/commit/2ed9b49)) -* **InstantSearch:** add specific `react-instantsearch ${version}` agent (#1844) ([a1113bc](https://github.com/algolia/instantsearch.js/commit/a1113bc)) -* **SFFV:** correct propTypes and add missing default values (#1845) ([a4c1b31](https://github.com/algolia/instantsearch.js/commit/a4c1b31)) -* **test:** add missing Snippet and Highliter snapshot ([4accce5](https://github.com/algolia/instantsearch.js/commit/4accce5)) -* **widgets:** replace setImmediate use with Promise use when update is needed (#1811) ([17e2497](https://github.com/algolia/instantsearch.js/commit/17e2497)) - - -### Features - -* **Menu, connectMenu:** add search for facet values (#1822) ([a6c513e](https://github.com/algolia/instantsearch.js/commit/a6c513e)) -* **snippet:** add a snippet widget to be able to highlight snippet results (#1797) ([2aecc40](https://github.com/algolia/instantsearch.js/commit/2aecc40)) -* **widgets:** add transformItems to be able to sort and filter (#1809) ([ba539f0](https://github.com/algolia/instantsearch.js/commit/ba539f0)) - - - - -# [2.1.0](https://github.com/algolia/instantsearch.js/compare/v2.0.1...v2.1.0) (2017-01-04) - - -### Bug Fixes - -* **createInstantSearchManager:** drop outdated response (#1765) ([76c5312](https://github.com/algolia/instantsearch.js/commit/76c5312)) -* **highlight:** highlight should work even if the attribute is missing (#1791) ([5b79b15](https://github.com/algolia/instantsearch.js/commit/5b79b15)), closes [#1790](https://github.com/algolia/instantsearch.js/issues/1790) -* **InfiniteHits:** better classname to loadmore btn (#1789) ([ad2ded3](https://github.com/algolia/instantsearch.js/commit/ad2ded3)) -* **starRatings:** click on selected range doesn't unselect it (#1766) ([beacc72](https://github.com/algolia/instantsearch.js/commit/beacc72)) -* **website:** broken demo links (#1802) ([0abe2f5](https://github.com/algolia/instantsearch.js/commit/0abe2f5)) -* **widgets:** add 300px width for the default SearchBox (#1803) ([bf5d791](https://github.com/algolia/instantsearch.js/commit/bf5d791)) - - -### Features - -* **InfiniteHits:** Add class to load more button (#1787) ([416febd](https://github.com/algolia/instantsearch.js/commit/416febd)) -* **RefinementList, connectRefinementList:** allow to search for facet values ([e086a81](https://github.com/algolia/instantsearch.js/commit/e086a81)) - - - - -## [2.0.1](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.1) (2016-12-15) - - -### Bug Fixes - -* **connectRange:** when unfinite numbers are passed throw ([75bec0d](https://github.com/algolia/instantsearch.js/commit/75bec0d)) -* **react-native:** use View as a container for react-native (#1729) ([5b76f75](https://github.com/algolia/instantsearch.js/commit/5b76f75)), closes [#1730](https://github.com/algolia/instantsearch.js/issues/1730) -* **SearchBox:** autocomplete was not disabled by default (#1742) ([bc76618](https://github.com/algolia/instantsearch.js/commit/bc76618)) -* **starRating:** call createURL with the right interface (min/max) (#1747) ([f9ab9b6](https://github.com/algolia/instantsearch.js/commit/f9ab9b6)) - - - - -## [2.0.0](https://github.com/algolia/instantsearch.js/compare/v2.0.0...v2.0.0) (2016-12-08) - -First release of `react-instantsearch` diff --git a/packages/react-instantsearch-native/README.md b/packages/react-instantsearch-native/README.md deleted file mode 100644 index 3f84a43a88..0000000000 --- a/packages/react-instantsearch-native/README.md +++ /dev/null @@ -1,13 +0,0 @@ - - -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - -- [react-instantsearch-native](#react-instantsearch-native) - - - -# react-instantsearch-native - -This is the [React Native](https://facebook.github.io/react-native) version of Algolia's `instantsearch` library. - -Go to the [React InstantSearch website](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/) or the [React InstantSearch GitHub repository](https://github.com/algolia/instantsearch.js) for more information. diff --git a/packages/react-instantsearch-native/package.json b/packages/react-instantsearch-native/package.json deleted file mode 100644 index 6aaa435828..0000000000 --- a/packages/react-instantsearch-native/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "react-instantsearch-native", - "version": "6.40.4", - "description": "⚡ Lightning-fast search for React Native, by Algolia", - "main": "dist/cjs/index.js", - "module": "dist/es/index.js", - "sideEffects": false, - "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/", - "repository": { - "type": "git", - "url": "https://github.com/algolia/instantsearch.js" - }, - "author": { - "name": "Algolia, Inc.", - "url": "https://www.algolia.com" - }, - "keywords": [ - "algolia", - "components", - "fast", - "instantsearch", - "react", - "react-native", - "search" - ], - "files": [ - "README.md", - "dist" - ], - "scripts": { - "clean": "rm -rf dist", - "watch": "yarn build:cjs --watch", - "build": "yarn build:cjs && yarn build:es", - "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", - "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet" - }, - "dependencies": { - "@babel/runtime": "^7.1.2", - "algoliasearch": ">= 3.27.1 < 5", - "react-instantsearch-core": "6.40.4" - }, - "peerDependencies": { - "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.3.0 < 19", - "react-native": ">= 0.54.0" - } -} diff --git a/packages/react-instantsearch-native/src/index.ts b/packages/react-instantsearch-native/src/index.ts deleted file mode 100644 index 88eee85db4..0000000000 --- a/packages/react-instantsearch-native/src/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -// Core -export { createConnector } from 'react-instantsearch-core'; -export { HIGHLIGHT_TAGS } from 'react-instantsearch-core'; -export { translatable } from 'react-instantsearch-core'; - -// Widgets -export { Configure } from 'react-instantsearch-core'; -export { ExperimentalConfigureRelatedItems } from 'react-instantsearch-core'; -export { - DynamicWidgets, - ExperimentalDynamicWidgets, -} from 'react-instantsearch-core'; -export { QueryRuleContext } from 'react-instantsearch-core'; -export { Index } from 'react-instantsearch-core'; -export { InstantSearch } from 'react-instantsearch-core'; - -// Connectors -export { connectAutoComplete } from 'react-instantsearch-core'; -export { connectBreadcrumb } from 'react-instantsearch-core'; -export { connectConfigure } from 'react-instantsearch-core'; -export { EXPERIMENTAL_connectConfigureRelatedItems } from 'react-instantsearch-core'; -export { - EXPERIMENTAL_connectDynamicWidgets, - connectDynamicWidgets, -} from 'react-instantsearch-core'; -export { connectCurrentRefinements } from 'react-instantsearch-core'; -export { connectGeoSearch } from 'react-instantsearch-core'; -export { connectHierarchicalMenu } from 'react-instantsearch-core'; -export { connectHighlight } from 'react-instantsearch-core'; -export { connectHitInsights } from 'react-instantsearch-core'; -export { connectHits } from 'react-instantsearch-core'; -export { connectHitsPerPage } from 'react-instantsearch-core'; -export { connectInfiniteHits } from 'react-instantsearch-core'; -export { connectMenu } from 'react-instantsearch-core'; -export { connectNumericMenu } from 'react-instantsearch-core'; -export { connectPagination } from 'react-instantsearch-core'; -export { connectPoweredBy } from 'react-instantsearch-core'; -export { connectQueryRules } from 'react-instantsearch-core'; -export { connectRange } from 'react-instantsearch-core'; -export { connectRefinementList } from 'react-instantsearch-core'; -export { connectScrollTo } from 'react-instantsearch-core'; -export { connectSearchBox } from 'react-instantsearch-core'; -export { connectRelevantSort } from 'react-instantsearch-core'; -export { connectSortBy } from 'react-instantsearch-core'; -export { connectStateResults } from 'react-instantsearch-core'; -export { connectStats } from 'react-instantsearch-core'; -export { connectToggleRefinement } from 'react-instantsearch-core'; diff --git a/packages/react-instantsearch-hooks-router-nextjs/CHANGELOG.md b/packages/react-instantsearch-router-nextjs/CHANGELOG.md similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/CHANGELOG.md rename to packages/react-instantsearch-router-nextjs/CHANGELOG.md diff --git a/packages/react-instantsearch-hooks-router-nextjs/README.md b/packages/react-instantsearch-router-nextjs/README.md similarity index 82% rename from packages/react-instantsearch-hooks-router-nextjs/README.md rename to packages/react-instantsearch-router-nextjs/README.md index c0fd3976e4..e54a96ff42 100644 --- a/packages/react-instantsearch-hooks-router-nextjs/README.md +++ b/packages/react-instantsearch-router-nextjs/README.md @@ -2,7 +2,7 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* -- [react-instantsearch-hooks-router-nextjs](#react-instantsearch-hooks-router-nextjs) +- [react-instantsearch-router-nextjs](#react-instantsearch-router-nextjs) - [Installation](#installation) - [Usage](#usage) - [API](#api) @@ -12,29 +12,29 @@ -# react-instantsearch-hooks-router-nextjs +# react-instantsearch-router-nextjs -This package is a router for [React InstantSearch Hooks](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/) that is compatible with [Next.js](https://nextjs.org/) routing. +This package is a router for [React InstantSearch](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/) that is compatible with [Next.js](https://nextjs.org/) routing. > :warning: **This function cannot be used in conjunction with [`getStaticProps()`](https://nextjs.org/docs/api-reference/data-fetching/get-static-props). Use `getServerSideProps()` or client-side rendering instead.** ## Installation ```sh -yarn add react-instantsearch-hooks-router-nextjs +yarn add react-instantsearch-router-nextjs # or with npm -npm install react-instantsearch-hooks-router-nextjs +npm install react-instantsearch-router-nextjs ``` ## Usage You need to pass the Next.js router singleton that you can import from `next/router`. -If you are doing SSR with the `getServerState` and `InstantSearchSSRProvider` from `react-instantsearch-hooks-server`, you need to pass the `url` prop to `createInstantSearchRouterNext`'s `serverUrl` option : +If you are doing SSR with the `getServerState` and `InstantSearchSSRProvider` from `react-instantsearch/server`, you need to pass the `url` prop to `createInstantSearchRouterNext`'s `serverUrl` option : ```js import singletonRouter from 'next/router'; -import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs'; +import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs'; export default function Page({ serverState, url }) { return ( @@ -55,7 +55,7 @@ If you are not doing SSR but only CSR, you can omit the `serverUrl` option: ```js import singletonRouter from 'next/router'; -import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs'; +import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs'; export default function Page() { return ( @@ -74,7 +74,7 @@ Lastly, if you had custom routing logic in your app, you can pass it to the `cre ```js import singletonRouter from 'next/router'; -import { createInstantSearchRouterNext } from 'react-instantsearch-hooks-router-nextjs'; +import { createInstantSearchRouterNext } from 'react-instantsearch-router-nextjs'; export default function Page({ serverState, url }) { return ( @@ -118,7 +118,7 @@ For troubleshooting purposes, some other options are available : ## Troubleshooting -If you're experiencing issues, please refer to the [**Need help?**](https://algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/#need-help) section of the docs, or [open a new issue](https://github.com/algolia/instantsearch.js/issues/new?assignees=&labels=triage&template=BUG_REPORT.yml). +If you're experiencing issues, please refer to the [**Need help?**](https://algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/#need-help) section of the docs, or [open a new issue](https://github.com/algolia/instantsearch.js/issues/new?assignees=&labels=triage&template=BUG_REPORT.yml). ## Contributing @@ -139,13 +139,13 @@ Please read [our contribution process](https://github.com/algolia/instantsearch. ## License -React InstantSearch Hooks is [MIT licensed](../../LICENSE). +React InstantSearch is [MIT licensed](../../LICENSE). -[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch+Hooks&title=Feature%20request%3A%20 -[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch+Hooks -[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 -[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch+Hooks%22 +[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch +[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch&title=Feature%20request%3A%20 +[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch +[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch%22 diff --git a/packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/backButton.test.ts b/packages/react-instantsearch-router-nextjs/__tests__/e2e/backButton.test.ts similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/backButton.test.ts rename to packages/react-instantsearch-router-nextjs/__tests__/e2e/backButton.test.ts diff --git a/packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/nextLink.test.ts b/packages/react-instantsearch-router-nextjs/__tests__/e2e/nextLink.test.ts similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/nextLink.test.ts rename to packages/react-instantsearch-router-nextjs/__tests__/e2e/nextLink.test.ts diff --git a/packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/utils.ts b/packages/react-instantsearch-router-nextjs/__tests__/e2e/utils.ts similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/__tests__/e2e/utils.ts rename to packages/react-instantsearch-router-nextjs/__tests__/e2e/utils.ts diff --git a/packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-cjs-module.cjs b/packages/react-instantsearch-router-nextjs/__tests__/module/is-cjs-module.cjs similarity index 65% rename from packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-cjs-module.cjs rename to packages/react-instantsearch-router-nextjs/__tests__/module/is-cjs-module.cjs index e81061759d..25f12ad4d2 100644 --- a/packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-cjs-module.cjs +++ b/packages/react-instantsearch-router-nextjs/__tests__/module/is-cjs-module.cjs @@ -2,8 +2,8 @@ const assert = require('assert'); -const ReactInstantSearchRouterNext = require('react-instantsearch-hooks-router-nextjs'); +const ReactInstantSearchRouterNext = require('react-instantsearch-router-nextjs'); assert.ok(ReactInstantSearchRouterNext); -console.log('react-instantsearch-hooks-router-nextjs is valid CJS'); +console.log('react-instantsearch-router-nextjs is valid CJS'); diff --git a/packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-es-module.mjs b/packages/react-instantsearch-router-nextjs/__tests__/module/is-es-module.mjs similarity index 64% rename from packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-es-module.mjs rename to packages/react-instantsearch-router-nextjs/__tests__/module/is-es-module.mjs index 45f90ca3a6..98b93a46b1 100644 --- a/packages/react-instantsearch-hooks-router-nextjs/__tests__/module/is-es-module.mjs +++ b/packages/react-instantsearch-router-nextjs/__tests__/module/is-es-module.mjs @@ -1,8 +1,8 @@ /* eslint-disable no-console */ import assert from 'assert'; -import * as ReactInstantSearchRouterNext from 'react-instantsearch-hooks-router-nextjs'; +import * as ReactInstantSearchRouterNext from 'react-instantsearch-router-nextjs'; assert.ok(ReactInstantSearchRouterNext); -console.log('react-instantsearch-hooks-router-nextjs is valid ESM'); +console.log('react-instantsearch-router-nextjs is valid ESM'); diff --git a/packages/react-instantsearch-hooks-router-nextjs/e2e.d.ts b/packages/react-instantsearch-router-nextjs/e2e.d.ts similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/e2e.d.ts rename to packages/react-instantsearch-router-nextjs/e2e.d.ts diff --git a/packages/react-instantsearch-hooks-router-nextjs/package.json b/packages/react-instantsearch-router-nextjs/package.json similarity index 86% rename from packages/react-instantsearch-hooks-router-nextjs/package.json rename to packages/react-instantsearch-router-nextjs/package.json index ebe885866c..a26515545f 100644 --- a/packages/react-instantsearch-hooks-router-nextjs/package.json +++ b/packages/react-instantsearch-router-nextjs/package.json @@ -1,7 +1,7 @@ { - "name": "react-instantsearch-hooks-router-nextjs", + "name": "react-instantsearch-router-nextjs", "version": "6.47.3", - "description": "React InstantSearch Hooks Router for Next.js", + "description": "React InstantSearch Router for Next.js", "source": "src/index.ts", "types": "dist/es/index.d.ts", "main": "dist/cjs/index.js", @@ -14,7 +14,7 @@ }, "sideEffects": false, "license": "MIT", - "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react-hooks/", + "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/", "repository": { "type": "git", "url": "https://github.com/algolia/instantsearch.js" @@ -44,12 +44,12 @@ "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", "test:exports": "node ./__tests__/module/is-es-module.mjs && node ./__tests__/module/is-cjs-module.cjs", - "test:start-server": "yarn workspace example-react-instantsearch-hooks-next-routing-example build && yarn workspace example-react-instantsearch-hooks-next-routing-example start", + "test:start-server": "yarn workspace example-react-instantsearch-next-routing-example build && yarn workspace example-react-instantsearch-next-routing-example start", "test:e2e": "start-server-and-test test:start-server 3000 'wdio run ./wdio.conf.cjs'" }, "dependencies": { "instantsearch.js": "4.56.8", - "react-instantsearch-hooks": "6.47.3" + "react-instantsearch-core": "6.47.3" }, "devDependencies": { "@types/jasmine": "3.3.16", diff --git a/packages/react-instantsearch-hooks-router-nextjs/src/index.ts b/packages/react-instantsearch-router-nextjs/src/index.ts similarity index 98% rename from packages/react-instantsearch-hooks-router-nextjs/src/index.ts rename to packages/react-instantsearch-router-nextjs/src/index.ts index 283ffabff6..c8c3d52c59 100644 --- a/packages/react-instantsearch-hooks-router-nextjs/src/index.ts +++ b/packages/react-instantsearch-router-nextjs/src/index.ts @@ -13,7 +13,7 @@ type CreateInstantSearchRouterNextOptions = { * * @example * import singletonRouter from 'next/router'; - * import { createInstantSearchNextRouter } from 'react-instantsearch-hooks-router-nextjs'; + * import { createInstantSearchNextRouter } from 'react-instantsearch-router-nextjs'; * * const router = createInstantSearchNextRouter({ singletonRouter }); */ @@ -59,7 +59,7 @@ type CreateInstantSearchRouterNextOptions = { /** * Options passed to the underlying history router. - * See https://www.algolia.com/doc/api-reference/widgets/history-router/react-hooks/ + * See https://www.algolia.com/doc/api-reference/widgets/history-router/react/ * for the list of available options. */ routerOptions?: Partial< diff --git a/packages/react-instantsearch-hooks-router-nextjs/tsconfig.declaration.json b/packages/react-instantsearch-router-nextjs/tsconfig.declaration.json similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/tsconfig.declaration.json rename to packages/react-instantsearch-router-nextjs/tsconfig.declaration.json diff --git a/packages/react-instantsearch-hooks-router-nextjs/tsconfig.wdio.json b/packages/react-instantsearch-router-nextjs/tsconfig.wdio.json similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/tsconfig.wdio.json rename to packages/react-instantsearch-router-nextjs/tsconfig.wdio.json diff --git a/packages/react-instantsearch-hooks-router-nextjs/wdio.conf.cjs b/packages/react-instantsearch-router-nextjs/wdio.conf.cjs similarity index 100% rename from packages/react-instantsearch-hooks-router-nextjs/wdio.conf.cjs rename to packages/react-instantsearch-router-nextjs/wdio.conf.cjs diff --git a/packages/react-instantsearch/CHANGELOG.md b/packages/react-instantsearch/CHANGELOG.md index 17aed471db..2b4129ab53 100644 --- a/packages/react-instantsearch/CHANGELOG.md +++ b/packages/react-instantsearch/CHANGELOG.md @@ -3,15 +3,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. -## [6.40.4](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.40.3...react-instantsearch@6.40.4) (2023-07-25) +## [6.47.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.2...react-instantsearch-hooks-web@6.47.3) (2023-07-27) -**Note:** Version bump only for package react-instantsearch + +### Bug Fixes + +* add a future warning when the package name changes ([#5778](https://github.com/algolia/instantsearch.js/issues/5778)) ([3d22ee4](https://github.com/algolia/instantsearch.js/commit/3d22ee45e1f03a443323a371621262f1fe45e664)) + + + + + +## [6.47.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.1...react-instantsearch-hooks-web@6.47.2) (2023-07-25) + +**Note:** Version bump only for package react-instantsearch-hooks-web -## [6.40.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.40.2...react-instantsearch@6.40.3) (2023-07-19) +## [6.47.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.47.0...react-instantsearch-hooks-web@6.47.1) (2023-07-19) ### Bug Fixes @@ -22,58 +33,223 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline -## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.40.1...react-instantsearch@6.40.2) (2023-07-18) +# [6.47.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.46.0...react-instantsearch-hooks-web@6.47.0) (2023-07-18) + + +### Features + +* **react-instantsearch-hooks web:** rename `` translation ([#5756](https://github.com/algolia/instantsearch.js/issues/5756)) ([6c70035](https://github.com/algolia/instantsearch.js/commit/6c700350377d69a71b8ed44f70952d33ed81d085)) + + + + + +## [6.46.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.45.1...react-instantsearch-hooks-web@6.46.0) (2023-07-10) + + +### Bug Fixes + +* **url:** base createURL on UiState instead of SearchParameters ([#5696](https://github.com/algolia/instantsearch.js/issues/5696)) ([7e2c8a2](https://github.com/algolia/instantsearch.js/commit/7e2c8a295a6fc5ba36d9482f645ef55b422d5e75)), closes [#5694](https://github.com/algolia/instantsearch.js/issues/5694) + + + + + +## [6.45.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.45.0...react-instantsearch-hooks-web@6.45.1) (2023-07-04) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.45.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.3...react-instantsearch-hooks-web@6.45.0) (2023-06-20) + +**Note:** Version bump only for package react-instantsearch-hooks-web -**Note:** Version bump only for package react-instantsearch +## [6.44.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.2...react-instantsearch-hooks-web@6.44.3) (2023-06-13) -## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.40.0...react-instantsearch@6.40.1) (2023-06-20) +**Note:** Version bump only for package react-instantsearch-hooks-web -**Note:** Version bump only for package react-instantsearch +## [6.44.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.1...react-instantsearch-hooks-web@6.44.2) (2023-06-05) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.44.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.44.0...react-instantsearch-hooks-web@6.44.1) (2023-05-30) + + +### Bug Fixes + +* **insights:** send default click event when using auxiliary pointer button ([#5634](https://github.com/algolia/instantsearch.js/issues/5634)) ([7e4a216](https://github.com/algolia/instantsearch.js/commit/7e4a2162f87596a384b35c97efa51db9bb6f8973)) + + + + + +## [6.43.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.43.0...react-instantsearch-hooks-web@6.43.1) (2023-05-16) + + +### Bug Fixes + +* **rangeinput:** allow input of numbers with precision ([#5541](https://github.com/algolia/instantsearch.js/issues/5541)) ([fb48951](https://github.com/algolia/instantsearch.js/commit/fb489513a8550528f3e2867be30fb380229ad188)) +* **this:** ensure all functions are able to be destructured ([#5611](https://github.com/algolia/instantsearch.js/issues/5611)) ([a8b5c1e](https://github.com/algolia/instantsearch.js/commit/a8b5c1e5bbd6afac39fce523f7d7c2ec02f51153)), closes [#5589](https://github.com/algolia/instantsearch.js/issues/5589) + + + + + +# [6.43.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.2...react-instantsearch-hooks-web@6.43.0) (2023-04-24) + + +### Bug Fixes + +* **lifecycle:** prevent extra network requests when unmounting multiple widgets ([#5602](https://github.com/algolia/instantsearch.js/issues/5602)) ([11458ee](https://github.com/algolia/instantsearch.js/commit/11458eee7e7f0f3e9c5f368584a16f58646b1cdd)) + + +### Features + + +* **insights:** add insights option to InstantSearch ([#5488](https://github.com/algolia/instantsearch.js/issues/5488)) ([9031573](https://github.com/algolia/instantsearch.js/commit/9031573807fa6803dcfae9f33d61b8f111f68423)) ([#5578](https://github.com/algolia/instantsearch.js/issues/5578)) ([8fb517f](https://github.com/algolia/instantsearch.js/commit/8fb517f15381ecb32ea00cf4b01a0fd5e70e1d17)) ([#5545](https://github.com/algolia/instantsearch.js/issues/5545)) ([99a0972](https://github.com/algolia/instantsearch.js/commit/99a0972663b8f3284cac3b5621571ced7a33908f)) ([#5493](https://github.com/algolia/instantsearch.js/issues/5493)) ([cff723f](https://github.com/algolia/instantsearch.js/commit/cff723fc95a90ebb2ed14c46c51ab05764835a47)) +* **insights:** always pass Algolia credentials locally ([#5554](https://github.com/algolia/instantsearch.js/issues/5554)) ([654ab81](https://github.com/algolia/instantsearch.js/commit/654ab81e1669354c249710b6756610fba35d54b4)) ([#5558](https://github.com/algolia/instantsearch.js/issues/5558)) ([82144c0](https://github.com/algolia/instantsearch.js/commit/82144c0a0b18e6b47d6f508e5c670a9de274c121)) ([#5529](https://github.com/algolia/instantsearch.js/issues/5529)) ([8537f8f](https://github.com/algolia/instantsearch.js/commit/8537f8f7a10bcaf053ff62180c082e077b1b052d)) +* **insights:** annotate events with algoliaSource ([#5580](https://github.com/algolia/instantsearch.js/issues/5580)) ([c419307](https://github.com/algolia/instantsearch.js/commit/c419307a5f7fe46d5032c9437a17c8e3dad57fe5)) +* **insights:** automatically load search-insights if not passed ([#5484](https://github.com/algolia/instantsearch.js/issues/5484)) ([a85797b](https://github.com/algolia/instantsearch.js/commit/a85797b503edc94e001c5bfb3b754db6cb556943)) +* **insights:** enable default click events on hits and infinite hits ([#5522](https://github.com/algolia/instantsearch.js/issues/5522)) ([271bd12](https://github.com/algolia/instantsearch.js/commit/271bd12e34bc55656976bb53c90282193083eb86)) ([#5527](https://github.com/algolia/instantsearch.js/issues/5527)) ([0e55821](https://github.com/algolia/instantsearch.js/commit/0e558213c807cd17d592fadec052f3d1fc692e6c)) +* **insights:** prevent potential errors ([#5487](https://github.com/algolia/instantsearch.js/issues/5487)) ([33fe510](https://github.com/algolia/instantsearch.js/commit/33fe510307e4b382a5ba1153a0eaf160420acd11)) ([#5606](https://github.com/algolia/instantsearch.js/issues/5606)) ([bdd9290](https://github.com/algolia/instantsearch.js/commit/bdd92901b59ae4e5d7311eadfbf53ed656bbaf4a)) ([#5512](https://github.com/algolia/instantsearch.js/issues/5512)) ([85dfbc9](https://github.com/algolia/instantsearch.js/commit/85dfbc9ebd722fbe6a7e1bd056950fdbcc16d8d9)) +* **metadata:** register metadata around middleware ([#5492](https://github.com/algolia/instantsearch.js/issues/5492)) ([3e72ec8](https://github.com/algolia/instantsearch.js/commit/3e72ec82894a05a071328a4802d2f764233fe005)) -## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.39.1...react-instantsearch@6.39.2) (2023-05-16) -**Note:** Version bump only for package react-instantsearch +## [6.42.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.1...react-instantsearch-hooks-web@6.42.2) (2023-04-11) +**Note:** Version bump only for package react-instantsearch-hooks-web -## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.39.0...react-instantsearch@6.39.1) (2023-03-21) -**Note:** Version bump only for package react-instantsearch +## [6.42.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.42.0...react-instantsearch-hooks-web@6.42.1) (2023-03-28) +**Note:** Version bump only for package react-instantsearch-hooks-web -## [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.38.3...react-instantsearch@6.39.0) (2023-01-26) -**Note:** Version bump only for package react-instantsearch +## [6.42.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.41.0...react-instantsearch-hooks-web@6.42.0) (2023-03-21) + + +### Bug Fixes + +* **searchbox:** add aria-hidden to svg icons ([#5547](https://github.com/algolia/instantsearch.js/issues/5547)) ([50344e3](https://github.com/algolia/instantsearch.js/commit/50344e3b14c22c886415c0e7d799aca778dc39ab)), closes [#5546](https://github.com/algolia/instantsearch.js/issues/5546) + + + + + +## [6.41.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.1...react-instantsearch-hooks-web@6.41.0) (2023-03-07) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.40.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.1...react-instantsearch-hooks-web@6.40.2) (2023-02-28) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.40.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.40.0...react-instantsearch-hooks-web@6.40.1) (2023-02-21) + + +### Bug Fixes + +* **breadcrumb:** guard against undefined facets ([#5482](https://github.com/algolia/instantsearch.js/issues/5482)) ([3159afe](https://github.com/algolia/instantsearch.js/commit/3159afe57472fe2b669dceb5f1ee638b658f7f52)) + + + + + +## [6.40.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.3...react-instantsearch-hooks-web@6.40.0) (2023-02-14) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.39.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.2...react-instantsearch-hooks-web@6.39.3) (2023-02-07) + +**Note:** Version bump only for package react-instantsearch-hooks-web + + + + + +## [6.39.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.1...react-instantsearch-hooks-web@6.39.2) (2023-01-30) + + +### Bug Fixes + +* **infiniteHits:** read cache correctly when search is loading ([#5461](https://github.com/algolia/instantsearch.js/issues/5461)) ([bfabe00](https://github.com/algolia/instantsearch.js/commit/bfabe002a26e15e13b33200c355379f4e3c60f21)) + + + + + +## [6.39.1](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.39.0...react-instantsearch-hooks-web@6.39.1) (2023-01-26) + + +### Bug Fixes + +* **dependencies:** update typescript ([#5454](https://github.com/algolia/instantsearch.js/issues/5454)) ([0e6bb48](https://github.com/algolia/instantsearch.js/commit/0e6bb485a31cd3294436ac9902c2c2662dfcdf8b)) +* **HierarchicalMenu:** don't give --parent class if data is empty ([#5458](https://github.com/algolia/instantsearch.js/issues/5458)) ([1d1a209](https://github.com/algolia/instantsearch.js/commit/1d1a209992e86b720939607cd22e37a04e865195)), closes [/github.com/algolia/instantsearch/blob/f84c01b2f66ac279f7e33fafe5f1cd559436edef/packages/instantsearch.js/src/components/RefinementList/RefinementList.tsx#L175-L179](https://github.com//github.com/algolia/instantsearch/blob/f84c01b2f66ac279f7e33fafe5f1cd559436edef/packages/instantsearch.js/src/components/RefinementList/RefinementList.tsx/issues/L175-L179) + + + + + +# [6.39.0](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.3...react-instantsearch-hooks-web@6.39.0) (2023-01-25) + + +### Features + +* **react-instantsearch-hooks-web:** Add stats widget and ui component ([#5427](https://github.com/algolia/instantsearch.js/issues/5427)) ([d07cf0d](https://github.com/algolia/instantsearch.js/commit/d07cf0d0310bf4e49d4a4c2142b3783d9bcda79d)) +* **rendering:** always render with current state ([#5429](https://github.com/algolia/instantsearch.js/issues/5429)) ([920e951](https://github.com/algolia/instantsearch.js/commit/920e951f03aada0e6a1ce16bc389a82a2f00b202)) +* **rendering:** revert search state on error ([#5438](https://github.com/algolia/instantsearch.js/issues/5438)) ([732fcac](https://github.com/algolia/instantsearch.js/commit/732fcac79ea1f51b19f62d5c4bf1fdf22619fa73)) + + -## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.38.2...react-instantsearch@6.38.3) (2023-01-09) +## [6.38.3](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.2...react-instantsearch-hooks-web@6.38.3) (2023-01-09) -**Note:** Version bump only for package react-instantsearch +**Note:** Version bump only for package react-instantsearch-hooks-web -## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch@6.38.1...react-instantsearch@6.38.2) (2023-01-03) +## [6.38.2](https://github.com/algolia/instantsearch.js/compare/react-instantsearch-hooks-web@6.38.1...react-instantsearch-hooks-web@6.38.2) (2023-01-03) -**Note:** Version bump only for package react-instantsearch +**Note:** Version bump only for package react-instantsearch-hooks-web diff --git a/packages/react-instantsearch/README.md b/packages/react-instantsearch/README.md index ca76b9bc71..9f3749bd2b 100644 --- a/packages/react-instantsearch/README.md +++ b/packages/react-instantsearch/README.md @@ -3,11 +3,122 @@ **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* - [react-instantsearch](#react-instantsearch) + - [Why](#why) + - [Installation](#installation) + - [Getting started](#getting-started) + - [Documentation](#documentation) + - [Playground](#playground) + - [Contributing](#contributing) + - [License](#license) # react-instantsearch -This is the [React](https://facebook.github.io/react) version of Algolia's `instantsearch` library. +React InstantSearch is an open-source React library that lets you create an instant search result experience using [Algolia][algolia-website]’s search API. It is part of the InstantSearch family: -Go to the [React InstantSearch website](https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/) or the [React InstantSearch GitHub repository](https://github.com/algolia/instantsearch.js) for more information. +**React InstantSearch** | [InstantSearch.js][instantsearch.js-github] | [Angular InstantSearch][instantsearch-angular-github] | [Vue InstantSearch][instantsearch-vue-github] | [InstantSearch Android][instantsearch-android-github] | [InstantSearch iOS][instantsearch-ios-github] + +## Why + +You should be using React InstantSearch if you want to: + +* Design search experiences with best practices +* Customize your components at will +* Follow React principles + +Note: If you are working with React Native, or otherwise do not use the DOM, check out `react-instantsearch-core` instead. + +## Installation + +React InstantSearch is available on the npm registry. It relies on [`algoliasearch`](https://github.com/algolia/algoliasearch-client-javascript) to communicate with Algolia APIs. + +```sh +yarn add algoliasearch react-instantsearch +# or +npm install algoliasearch react-instantsearch +``` + +## Getting started + +Using React InstantSearch is as simple as adding these components to your app: + +```javascript +import React from 'react'; +import ReactDOM from 'react-dom'; +import algoliasearch from 'algoliasearch/lite'; +import { InstantSearch, SearchBox, Hits } from 'react-instantsearch'; + +const searchClient = algoliasearch( + 'latency', + '6be0576ff61c053d5f9a3225e2a90f76' +); + +const App = () => ( + + + + +); +``` + +

    + + Edit on CodeSandbox + +

    + +To learn more about the library, follow the [getting started guide][doc-getting-started]. + +## Documentation + +The documentation is available on [algolia.com/doc][doc]. + +## Playground + +You can get to know React InstantSearch on [this playground][doc-playground]. + +Start by [adding components][doc-getting-started] and tweaking the display. Once you get more familiar with the library, you can learn more advanced concepts in [our guides][doc-guides]. + +## Contributing + +We welcome all contributors, from casual to regular 💙 + +- **Bug report**. Is something not working as expected? [Send a bug report][contributing-bugreport]. +- **Feature request**. Would you like to add something to the library? [Send a feature request][contributing-featurerequest]. +- **Documentation**. Did you find a typo in the doc? [Open an issue][contributing-newissue] and we'll take care of it. +- **Development**. If you don't know where to start, you can check the open issues that are [tagged easy][contributing-label-easy], the [bugs][contributing-label-bug] or [chores][contributing-label-chore]. + +To start contributing to code, you need to: + +1. [Fork the project](https://help.github.com/articles/fork-a-repo/) +1. [Clone the repository](https://help.github.com/articles/cloning-a-repository/) +1. Install the dependencies: `yarn` + +Please read [our contribution process](https://github.com/algolia/instantsearch.js/blob/master/CONTRIBUTING.md) to learn more. + +## License + +React InstantSearch is [MIT licensed](../../LICENSE). + + + +[doc]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/ +[doc-getting-started]: https://www.algolia.com/doc/guides/building-search-ui/getting-started/react/ +[doc-guides]: https://www.algolia.com/doc/guides/building-search-ui/going-further/server-side-rendering/react/ +[doc-playground]: https://codesandbox.io/s/github/algolia/instantsearch/tree/master/examples/react/default-theme +[algolia-website]: https://www.algolia.com/ +[instantsearch.js-github]: https://github.com/algolia/instantsearch.js +[instantsearch-android-github]: https://github.com/algolia/instantsearch-android +[instantsearch-ios-github]: https://github.com/algolia/instantsearch-ios +[instantsearch-vue-github]: https://github.com/algolia/vue-instantsearch +[instantsearch-angular-github]: https://github.com/algolia/angular-instantsearch +[contributing-bugreport]: https://github.com/algolia/instantsearch.js/issues/new?template=BUG_REPORT.yml&labels=triage,Library%3A%20React+InstantSearch +[contributing-featurerequest]: https://github.com/algolia/instantsearch.js/discussions/new?category=ideas&labels=triage,Library%3A%20React+InstantSearch&title=Feature%20request%3A%20 +[contributing-newissue]: https://github.com/algolia/instantsearch.js/issues/new?labels=triage,Library%3A%20React+InstantSearch +[contributing-label-easy]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22Difficulty%3A+Easy%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-bug]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Bug%22+label%3A%22Library%3A%20React+InstantSearch%22 +[contributing-label-chore]: https://github.com/algolia/instantsearch.js/issues?q=is%3Aissue+is%3Aopen+label%3A%22Type%3A+Chore%22+label%3A%22Library%3A%20React+InstantSearch%22 diff --git a/packages/react-instantsearch/connectors.js b/packages/react-instantsearch/connectors.js deleted file mode 100644 index 1a737ad660..0000000000 --- a/packages/react-instantsearch/connectors.js +++ /dev/null @@ -1,29 +0,0 @@ -export { connectAutoComplete } from 'react-instantsearch-core'; -export { connectBreadcrumb } from 'react-instantsearch-core'; -export { connectConfigure } from 'react-instantsearch-core'; -export { EXPERIMENTAL_connectConfigureRelatedItems } from 'react-instantsearch-core'; -export { - connectDynamicWidgets, - EXPERIMENTAL_connectDynamicWidgets, -} from 'react-instantsearch-core'; -export { connectCurrentRefinements } from 'react-instantsearch-core'; -export { connectGeoSearch } from 'react-instantsearch-core'; -export { connectHierarchicalMenu } from 'react-instantsearch-core'; -export { connectHighlight } from 'react-instantsearch-core'; -export { connectHitInsights } from 'react-instantsearch-core'; -export { connectHits } from 'react-instantsearch-core'; -export { connectHitsPerPage } from 'react-instantsearch-core'; -export { connectInfiniteHits } from 'react-instantsearch-core'; -export { connectMenu } from 'react-instantsearch-core'; -export { connectNumericMenu } from 'react-instantsearch-core'; -export { connectPagination } from 'react-instantsearch-core'; -export { connectPoweredBy } from 'react-instantsearch-core'; -export { connectRange } from 'react-instantsearch-core'; -export { connectRefinementList } from 'react-instantsearch-core'; -export { connectScrollTo } from 'react-instantsearch-core'; -export { connectSearchBox } from 'react-instantsearch-core'; -export { connectRelevantSort } from 'react-instantsearch-core'; -export { connectSortBy } from 'react-instantsearch-core'; -export { connectStateResults } from 'react-instantsearch-core'; -export { connectStats } from 'react-instantsearch-core'; -export { connectToggleRefinement } from 'react-instantsearch-core'; diff --git a/packages/react-instantsearch/dom.js b/packages/react-instantsearch/dom.js deleted file mode 100644 index 48dfad4799..0000000000 --- a/packages/react-instantsearch/dom.js +++ /dev/null @@ -1,34 +0,0 @@ -export { InstantSearch } from 'react-instantsearch-dom'; -export { Index } from 'react-instantsearch-dom'; -export { Breadcrumb } from 'react-instantsearch-dom'; -export { ClearRefinements } from 'react-instantsearch-dom'; -export { Configure } from 'react-instantsearch-dom'; -export { ExperimentalConfigureRelatedItems } from 'react-instantsearch-dom'; -export { - DynamicWidgets, - ExperimentalDynamicWidgets, -} from 'react-instantsearch-dom'; -export { CurrentRefinements } from 'react-instantsearch-dom'; -export { HierarchicalMenu } from 'react-instantsearch-dom'; -export { Highlight } from 'react-instantsearch-dom'; -export { Hits } from 'react-instantsearch-dom'; -export { HitsPerPage } from 'react-instantsearch-dom'; -export { InfiniteHits } from 'react-instantsearch-dom'; -export { Menu } from 'react-instantsearch-dom'; -export { MenuSelect } from 'react-instantsearch-dom'; -export { NumericMenu } from 'react-instantsearch-dom'; -export { Pagination } from 'react-instantsearch-dom'; -export { Panel } from 'react-instantsearch-dom'; -export { PoweredBy } from 'react-instantsearch-dom'; -export { RangeInput } from 'react-instantsearch-dom'; -export { RangeSlider } from 'react-instantsearch-dom'; -export { RatingMenu } from 'react-instantsearch-dom'; -export { RefinementList } from 'react-instantsearch-dom'; -export { ScrollTo } from 'react-instantsearch-dom'; -export { SearchBox } from 'react-instantsearch-dom'; -export { RelevantSort } from 'react-instantsearch-dom'; -export { Snippet } from 'react-instantsearch-dom'; -export { SortBy } from 'react-instantsearch-dom'; -export { Stats } from 'react-instantsearch-dom'; -export { ToggleRefinement } from 'react-instantsearch-dom'; -export { getInsightsAnonymousUserToken } from 'react-instantsearch-dom'; diff --git a/packages/react-instantsearch-hooks-web/global.d.ts b/packages/react-instantsearch/global.d.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/global.d.ts rename to packages/react-instantsearch/global.d.ts diff --git a/packages/react-instantsearch/index.js b/packages/react-instantsearch/index.js deleted file mode 100644 index 5315621351..0000000000 --- a/packages/react-instantsearch/index.js +++ /dev/null @@ -1 +0,0 @@ -export { createConnector } from 'react-instantsearch-core'; diff --git a/packages/react-instantsearch/native.js b/packages/react-instantsearch/native.js deleted file mode 100644 index 16e8957cbf..0000000000 --- a/packages/react-instantsearch/native.js +++ /dev/null @@ -1,8 +0,0 @@ -export { InstantSearch } from 'react-instantsearch-native'; -export { Index } from 'react-instantsearch-native'; -export { Configure } from 'react-instantsearch-native'; -export { ExperimentalConfigureRelatedItems } from 'react-instantsearch-native'; -export { - DynamicWidgets, - ExperimentalDynamicWidgets, -} from 'react-instantsearch-native'; diff --git a/packages/react-instantsearch/package.json b/packages/react-instantsearch/package.json index 35969f6ce7..5606dfb86b 100644 --- a/packages/react-instantsearch/package.json +++ b/packages/react-instantsearch/package.json @@ -1,23 +1,24 @@ { "name": "react-instantsearch", - "version": "6.40.4", - "description": "⚡ Lightning-fast search for React and React Native apps, by Algolia", - "main": "index.js", + "version": "6.47.3", + "description": "⚡ Lightning-fast search for React, by Algolia", + "source": "src/index.ts", + "types": "dist/es/index.d.ts", + "main": "dist/cjs/index.js", "module": "dist/es/index.js", - "files": [ - "connectors.js", - "dom.js", - "index.js", - "native.js", - "server.js", - "dist" - ], + "type": "module", + "exports": { + ".": { + "import": "./dist/es/index.js", + "require": "./dist/cjs/index.js" + } + }, "sideEffects": false, "license": "MIT", "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/react/", "repository": { "type": "git", - "url": "https://github.com/algolia/instantsearch.js" + "url": "https://github.com/algolia/instantsearch" }, "author": { "name": "Algolia, Inc.", @@ -29,27 +30,30 @@ "fast", "instantsearch", "react", - "react-dom", - "react-native", "search" ], + "files": [ + "README.md", + "dist" + ], "scripts": { "clean": "rm -rf dist", - "build": "yarn build:cjs && yarn build:es && yarn build:umd", - "build:cjs": "BABEL_ENV=cjs babel connectors.js dom.js index.js native.js server.js --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist --quiet", - "build:es": "BABEL_ENV=es babel connectors.js dom.js index.js native.js server.js --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --quiet", + "watch": "yarn build:cjs --watch", + "build": "yarn build:cjs && yarn build:es && yarn build:umd && yarn build:types", + "build:cjs": "BABEL_ENV=cjs babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/cjs --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet && ../../scripts/prepare-cjs.sh", + "build:es": "BABEL_ENV=es babel src --root-mode upward --extensions '.js,.ts,.tsx' --out-dir dist/es --ignore '**/__tests__/**/*','**/__mocks__/**/*' --quiet", "build:umd": "BABEL_ENV=rollup rollup -c rollup.config.js", - "preparePackageFolder": "cp package.json dist && cp ../../README.md dist", - "prepublishOnly": "yarn run preparePackageFolder" + "build:types": "tsc -p ./tsconfig.declaration.json --outDir ./dist/es", + "test:exports": "node ./test/module/is-es-module.mjs && node ./test/module/is-cjs-module.cjs" }, "dependencies": { "@babel/runtime": "^7.1.2", - "react-instantsearch-core": "6.40.4", - "react-instantsearch-dom": "6.40.4", - "react-instantsearch-native": "6.40.4" + "instantsearch.js": "4.56.8", + "react-instantsearch-core": "6.47.3" }, "peerDependencies": { "algoliasearch": ">= 3.1 < 5", - "react": ">= 16.3.0 < 19" + "react": ">= 16.8.0 < 19", + "react-dom": ">= 16.8.0 < 19" } } diff --git a/packages/react-instantsearch/rollup.config.js b/packages/react-instantsearch/rollup.config.js index d3781b2cf6..603f61ddb6 100644 --- a/packages/react-instantsearch/rollup.config.js +++ b/packages/react-instantsearch/rollup.config.js @@ -11,8 +11,8 @@ const clear = (x) => x.filter(Boolean); const version = process.env.VERSION || 'UNRELEASED'; const algolia = '© Algolia, inc.'; const link = 'https://github.com/algolia/instantsearch.js'; -const createBanner = () => - `/*! React InstantSearch ${version} | ${algolia} | ${link} */`; +const createBanner = (name) => + `/*! React InstantSearch${name} ${version} | ${algolia} | ${link} */`; const plugins = [ babel({ @@ -26,7 +26,13 @@ const plugins = [ preferBuiltins: false, extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json'], }), - commonjs(), + commonjs({ + namedExports: { + '../../node_modules/use-sync-external-store/shim/index.js': [ + 'useSyncExternalStore', + ], + }, + }), globals(), replace({ 'process.env.NODE_ENV': JSON.stringify('production'), @@ -37,18 +43,17 @@ const plugins = [ }), ]; -const createConfiguration = ({ input, name, minify = false } = {}) => ({ - input, - external: ['react', 'react-dom'], +const createConfiguration = ({ name, minify = false } = {}) => ({ + input: 'src/index.ts', + external: ['react'], output: { - file: `dist/umd/${name}${minify ? '.min' : ''}.js`, - name: `ReactInstantSearch.${name}`, + file: `dist/umd/ReactInstantSearch${name}${minify ? '.min' : ''}.js`, + name: `ReactInstantSearch${name}`, format: 'umd', globals: { react: 'React', - 'react-dom': 'ReactDOM', }, - banner: createBanner(), + banner: createBanner(name), sourcemap: true, }, plugins: plugins.concat( @@ -56,7 +61,7 @@ const createConfiguration = ({ input, name, minify = false } = {}) => ({ minify && uglify({ output: { - preamble: createBanner(), + preamble: createBanner(name), }, }), ]) @@ -64,36 +69,12 @@ const createConfiguration = ({ input, name, minify = false } = {}) => ({ }); export default [ - // Core createConfiguration({ - input: 'index.js', - name: 'Core', - }), - createConfiguration({ - input: 'index.js', - name: 'Core', - minify: true, + name: '', }), - // DOM - createConfiguration({ - input: 'dom.js', - name: 'Dom', - }), - createConfiguration({ - input: 'dom.js', - name: 'Dom', - minify: true, - }), - - // Connectors - createConfiguration({ - input: 'connectors.js', - name: 'Connectors', - }), createConfiguration({ - input: 'connectors.js', - name: 'Connectors', + name: '', minify: true, }), ]; diff --git a/packages/react-instantsearch/server.js b/packages/react-instantsearch/server.js deleted file mode 100644 index d8fb0d1a46..0000000000 --- a/packages/react-instantsearch/server.js +++ /dev/null @@ -1 +0,0 @@ -export { createInstantSearch } from 'react-instantsearch-dom/server'; diff --git a/packages/react-instantsearch-hooks-web/src/__tests__/common-connectors.test.tsx b/packages/react-instantsearch/src/__tests__/common-connectors.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/__tests__/common-connectors.test.tsx rename to packages/react-instantsearch/src/__tests__/common-connectors.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/__tests__/common-shared.test.tsx b/packages/react-instantsearch/src/__tests__/common-shared.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/__tests__/common-shared.test.tsx rename to packages/react-instantsearch/src/__tests__/common-shared.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/__tests__/common-widgets.test.tsx b/packages/react-instantsearch/src/__tests__/common-widgets.test.tsx similarity index 98% rename from packages/react-instantsearch-hooks-web/src/__tests__/common-widgets.test.tsx rename to packages/react-instantsearch/src/__tests__/common-widgets.test.tsx index c07ee43528..03cf526293 100644 --- a/packages/react-instantsearch-hooks-web/src/__tests__/common-widgets.test.tsx +++ b/packages/react-instantsearch/src/__tests__/common-widgets.test.tsx @@ -209,7 +209,7 @@ const testSetups: TestSetupsMap = { require('../../../instantsearch.js/package.json').version })`, `react-instantsearch (${ - require('../../../react-instantsearch-hooks/package.json').version + require('../../../react-instantsearch-core/package.json').version })`, `react (${require('react').version})`, ], diff --git a/packages/react-instantsearch/src/index.ts b/packages/react-instantsearch/src/index.ts new file mode 100644 index 0000000000..4cf3bff55c --- /dev/null +++ b/packages/react-instantsearch/src/index.ts @@ -0,0 +1,2 @@ +export * from 'react-instantsearch-core'; +export * from './widgets'; diff --git a/packages/react-instantsearch-hooks-web/src/types/PartialKeys.ts b/packages/react-instantsearch/src/types/PartialKeys.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/types/PartialKeys.ts rename to packages/react-instantsearch/src/types/PartialKeys.ts diff --git a/packages/react-instantsearch-hooks-web/src/types/Translatable.ts b/packages/react-instantsearch/src/types/Translatable.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/types/Translatable.ts rename to packages/react-instantsearch/src/types/Translatable.ts diff --git a/packages/react-instantsearch-hooks-web/src/types/index.ts b/packages/react-instantsearch/src/types/index.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/types/index.ts rename to packages/react-instantsearch/src/types/index.ts diff --git a/packages/react-instantsearch-hooks-web/src/ui/Breadcrumb.tsx b/packages/react-instantsearch/src/ui/Breadcrumb.tsx similarity index 98% rename from packages/react-instantsearch-hooks-web/src/ui/Breadcrumb.tsx rename to packages/react-instantsearch/src/ui/Breadcrumb.tsx index 868ca0b5d3..6b16e8cacd 100644 --- a/packages/react-instantsearch-hooks-web/src/ui/Breadcrumb.tsx +++ b/packages/react-instantsearch/src/ui/Breadcrumb.tsx @@ -3,7 +3,7 @@ import React from 'react'; import { cx } from './lib/cx'; import { isModifierClick } from './lib/isModifierClick'; -import type { useBreadcrumb } from 'react-instantsearch-hooks'; +import type { useBreadcrumb } from 'react-instantsearch-core'; export type BreadcrumbTranslations = { /** diff --git a/packages/react-instantsearch-hooks-web/src/ui/ClearRefinements.tsx b/packages/react-instantsearch/src/ui/ClearRefinements.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/ClearRefinements.tsx rename to packages/react-instantsearch/src/ui/ClearRefinements.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/CurrentRefinements.tsx b/packages/react-instantsearch/src/ui/CurrentRefinements.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/CurrentRefinements.tsx rename to packages/react-instantsearch/src/ui/CurrentRefinements.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/HierarchicalMenu.tsx b/packages/react-instantsearch/src/ui/HierarchicalMenu.tsx similarity index 98% rename from packages/react-instantsearch-hooks-web/src/ui/HierarchicalMenu.tsx rename to packages/react-instantsearch/src/ui/HierarchicalMenu.tsx index 688b1fa33e..e6175e767e 100644 --- a/packages/react-instantsearch-hooks-web/src/ui/HierarchicalMenu.tsx +++ b/packages/react-instantsearch/src/ui/HierarchicalMenu.tsx @@ -5,7 +5,7 @@ import { isModifierClick } from './lib/isModifierClick'; import { ShowMoreButton } from './ShowMoreButton'; import type { ShowMoreButtonTranslations } from './ShowMoreButton'; -import type { useHierarchicalMenu } from 'react-instantsearch-hooks'; +import type { useHierarchicalMenu } from 'react-instantsearch-core'; type HierarchicalMenuClassNames = { /** diff --git a/packages/react-instantsearch-hooks-web/src/ui/Highlight.tsx b/packages/react-instantsearch/src/ui/Highlight.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Highlight.tsx rename to packages/react-instantsearch/src/ui/Highlight.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/Hits.tsx b/packages/react-instantsearch/src/ui/Hits.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Hits.tsx rename to packages/react-instantsearch/src/ui/Hits.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/HitsPerPage.tsx b/packages/react-instantsearch/src/ui/HitsPerPage.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/HitsPerPage.tsx rename to packages/react-instantsearch/src/ui/HitsPerPage.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/InfiniteHits.tsx b/packages/react-instantsearch/src/ui/InfiniteHits.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/InfiniteHits.tsx rename to packages/react-instantsearch/src/ui/InfiniteHits.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/InternalHighlight.tsx b/packages/react-instantsearch/src/ui/InternalHighlight.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/InternalHighlight.tsx rename to packages/react-instantsearch/src/ui/InternalHighlight.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/Menu.tsx b/packages/react-instantsearch/src/ui/Menu.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Menu.tsx rename to packages/react-instantsearch/src/ui/Menu.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/Pagination.tsx b/packages/react-instantsearch/src/ui/Pagination.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Pagination.tsx rename to packages/react-instantsearch/src/ui/Pagination.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/PoweredBy.tsx b/packages/react-instantsearch/src/ui/PoweredBy.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/PoweredBy.tsx rename to packages/react-instantsearch/src/ui/PoweredBy.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/RangeInput.tsx b/packages/react-instantsearch/src/ui/RangeInput.tsx similarity index 98% rename from packages/react-instantsearch-hooks-web/src/ui/RangeInput.tsx rename to packages/react-instantsearch/src/ui/RangeInput.tsx index d05adf8cad..a029dcbd15 100644 --- a/packages/react-instantsearch-hooks-web/src/ui/RangeInput.tsx +++ b/packages/react-instantsearch/src/ui/RangeInput.tsx @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import { cx } from './lib/cx'; -import type { useRange } from 'react-instantsearch-hooks'; +import type { useRange } from 'react-instantsearch-core'; type RangeRenderState = ReturnType; diff --git a/packages/react-instantsearch-hooks-web/src/ui/RefinementList.tsx b/packages/react-instantsearch/src/ui/RefinementList.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/RefinementList.tsx rename to packages/react-instantsearch/src/ui/RefinementList.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/SearchBox.tsx b/packages/react-instantsearch/src/ui/SearchBox.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/SearchBox.tsx rename to packages/react-instantsearch/src/ui/SearchBox.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/ShowMoreButton.tsx b/packages/react-instantsearch/src/ui/ShowMoreButton.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/ShowMoreButton.tsx rename to packages/react-instantsearch/src/ui/ShowMoreButton.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/Snippet.tsx b/packages/react-instantsearch/src/ui/Snippet.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Snippet.tsx rename to packages/react-instantsearch/src/ui/Snippet.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/SortBy.tsx b/packages/react-instantsearch/src/ui/SortBy.tsx similarity index 95% rename from packages/react-instantsearch-hooks-web/src/ui/SortBy.tsx rename to packages/react-instantsearch/src/ui/SortBy.tsx index 7b050e225b..0821c2caf2 100644 --- a/packages/react-instantsearch-hooks-web/src/ui/SortBy.tsx +++ b/packages/react-instantsearch/src/ui/SortBy.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { cx } from './lib/cx'; -import type { UseSortByProps } from 'react-instantsearch-hooks'; +import type { UseSortByProps } from 'react-instantsearch-core'; export type SortByProps = Omit, 'onChange'> & Pick & diff --git a/packages/react-instantsearch-hooks-web/src/ui/Stats.tsx b/packages/react-instantsearch/src/ui/Stats.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/Stats.tsx rename to packages/react-instantsearch/src/ui/Stats.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/ToggleRefinement.tsx b/packages/react-instantsearch/src/ui/ToggleRefinement.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/ToggleRefinement.tsx rename to packages/react-instantsearch/src/ui/ToggleRefinement.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/Breadcrumb.test.tsx b/packages/react-instantsearch/src/ui/__tests__/Breadcrumb.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/Breadcrumb.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/Breadcrumb.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/ClearRefinements.test.tsx b/packages/react-instantsearch/src/ui/__tests__/ClearRefinements.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/ClearRefinements.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/ClearRefinements.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/CurrentRefinements.test.tsx b/packages/react-instantsearch/src/ui/__tests__/CurrentRefinements.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/CurrentRefinements.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/CurrentRefinements.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/HierarchicalMenu.test.tsx b/packages/react-instantsearch/src/ui/__tests__/HierarchicalMenu.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/HierarchicalMenu.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/HierarchicalMenu.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/Hits.test.tsx b/packages/react-instantsearch/src/ui/__tests__/Hits.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/Hits.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/Hits.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/HitsPerPage.test.tsx b/packages/react-instantsearch/src/ui/__tests__/HitsPerPage.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/HitsPerPage.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/HitsPerPage.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/InfiniteHits.test.tsx b/packages/react-instantsearch/src/ui/__tests__/InfiniteHits.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/InfiniteHits.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/InfiniteHits.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/InternalHighlight.test.tsx b/packages/react-instantsearch/src/ui/__tests__/InternalHighlight.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/InternalHighlight.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/InternalHighlight.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/Menu.test.tsx b/packages/react-instantsearch/src/ui/__tests__/Menu.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/Menu.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/Menu.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/Pagination.test.tsx b/packages/react-instantsearch/src/ui/__tests__/Pagination.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/Pagination.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/Pagination.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/PoweredBy.test.tsx b/packages/react-instantsearch/src/ui/__tests__/PoweredBy.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/PoweredBy.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/PoweredBy.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/RangeInput.test.tsx b/packages/react-instantsearch/src/ui/__tests__/RangeInput.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/RangeInput.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/RangeInput.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx b/packages/react-instantsearch/src/ui/__tests__/RefinementList.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/RefinementList.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/RefinementList.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/SearchBox.test.tsx b/packages/react-instantsearch/src/ui/__tests__/SearchBox.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/SearchBox.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/SearchBox.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/ShowMoreButton.test.tsx b/packages/react-instantsearch/src/ui/__tests__/ShowMoreButton.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/ShowMoreButton.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/ShowMoreButton.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/SortBy.test.tsx b/packages/react-instantsearch/src/ui/__tests__/SortBy.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/SortBy.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/SortBy.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/Stats.test.tsx b/packages/react-instantsearch/src/ui/__tests__/Stats.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/Stats.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/Stats.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/__tests__/ToggleRefinement.test.tsx b/packages/react-instantsearch/src/ui/__tests__/ToggleRefinement.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/__tests__/ToggleRefinement.test.tsx rename to packages/react-instantsearch/src/ui/__tests__/ToggleRefinement.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/lib/__tests__/isModifierClick.test.tsx b/packages/react-instantsearch/src/ui/lib/__tests__/isModifierClick.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/lib/__tests__/isModifierClick.test.tsx rename to packages/react-instantsearch/src/ui/lib/__tests__/isModifierClick.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/ui/lib/cx.ts b/packages/react-instantsearch/src/ui/lib/cx.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/lib/cx.ts rename to packages/react-instantsearch/src/ui/lib/cx.ts diff --git a/packages/react-instantsearch-hooks-web/src/ui/lib/isModifierClick.ts b/packages/react-instantsearch/src/ui/lib/isModifierClick.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/ui/lib/isModifierClick.ts rename to packages/react-instantsearch/src/ui/lib/isModifierClick.ts diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Breadcrumb.tsx b/packages/react-instantsearch/src/widgets/Breadcrumb.tsx similarity index 88% rename from packages/react-instantsearch-hooks-web/src/widgets/Breadcrumb.tsx rename to packages/react-instantsearch/src/widgets/Breadcrumb.tsx index 254e896f77..c185419dc8 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/Breadcrumb.tsx +++ b/packages/react-instantsearch/src/widgets/Breadcrumb.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useBreadcrumb } from 'react-instantsearch-hooks'; +import { useBreadcrumb } from 'react-instantsearch-core'; import { Breadcrumb as BreadcrumbUiComponent } from '../ui/Breadcrumb'; import type { BreadcrumbProps as BreadcrumbUiProps } from '../ui/Breadcrumb'; -import type { UseBreadcrumbProps } from 'react-instantsearch-hooks'; +import type { UseBreadcrumbProps } from 'react-instantsearch-core'; type UiProps = Pick< BreadcrumbUiProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/ClearRefinements.tsx b/packages/react-instantsearch/src/widgets/ClearRefinements.tsx similarity index 93% rename from packages/react-instantsearch-hooks-web/src/widgets/ClearRefinements.tsx rename to packages/react-instantsearch/src/widgets/ClearRefinements.tsx index d38f0fce84..b8bff3a83d 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/ClearRefinements.tsx +++ b/packages/react-instantsearch/src/widgets/ClearRefinements.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useClearRefinements } from 'react-instantsearch-hooks'; +import { useClearRefinements } from 'react-instantsearch-core'; import { ClearRefinements as ClearRefinementsUiComponent } from '../ui/ClearRefinements'; import type { ClearRefinementsProps as ClearRefinementsUiComponentProps } from '../ui/ClearRefinements'; -import type { UseClearRefinementsProps } from 'react-instantsearch-hooks'; +import type { UseClearRefinementsProps } from 'react-instantsearch-core'; type UiProps = Pick< ClearRefinementsUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/CurrentRefinements.tsx b/packages/react-instantsearch/src/widgets/CurrentRefinements.tsx similarity index 92% rename from packages/react-instantsearch-hooks-web/src/widgets/CurrentRefinements.tsx rename to packages/react-instantsearch/src/widgets/CurrentRefinements.tsx index 51e31575ae..0397378a8d 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/CurrentRefinements.tsx +++ b/packages/react-instantsearch/src/widgets/CurrentRefinements.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useCurrentRefinements } from 'react-instantsearch-hooks'; +import { useCurrentRefinements } from 'react-instantsearch-core'; import { CurrentRefinements as CurrentRefinementsUiComponent } from '../ui/CurrentRefinements'; import type { CurrentRefinementsProps as CurrentRefinementsUiComponentProps } from '../ui/CurrentRefinements'; -import type { UseCurrentRefinementsProps } from 'react-instantsearch-hooks'; +import type { UseCurrentRefinementsProps } from 'react-instantsearch-core'; type UiProps = Pick< CurrentRefinementsUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/HierarchicalMenu.tsx b/packages/react-instantsearch/src/widgets/HierarchicalMenu.tsx similarity index 95% rename from packages/react-instantsearch-hooks-web/src/widgets/HierarchicalMenu.tsx rename to packages/react-instantsearch/src/widgets/HierarchicalMenu.tsx index dc7b4eab6e..e1ae2a3136 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/HierarchicalMenu.tsx +++ b/packages/react-instantsearch/src/widgets/HierarchicalMenu.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useHierarchicalMenu } from 'react-instantsearch-hooks'; +import { useHierarchicalMenu } from 'react-instantsearch-core'; import { HierarchicalMenu as HierarchicalMenuUiComponent } from '../ui/HierarchicalMenu'; import type { HierarchicalMenuProps as HierarchicalMenuUiComponentProps } from '../ui/HierarchicalMenu'; -import type { UseHierarchicalMenuProps } from 'react-instantsearch-hooks'; +import type { UseHierarchicalMenuProps } from 'react-instantsearch-core'; type UiProps = Pick< HierarchicalMenuUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Highlight.tsx b/packages/react-instantsearch/src/widgets/Highlight.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/Highlight.tsx rename to packages/react-instantsearch/src/widgets/Highlight.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Hits.tsx b/packages/react-instantsearch/src/widgets/Hits.tsx similarity index 87% rename from packages/react-instantsearch-hooks-web/src/widgets/Hits.tsx rename to packages/react-instantsearch/src/widgets/Hits.tsx index f46d670c9f..5a99c67b67 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/Hits.tsx +++ b/packages/react-instantsearch/src/widgets/Hits.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import { useHits } from 'react-instantsearch-hooks'; +import { useHits } from 'react-instantsearch-core'; import { Hits as HitsUiComponent } from '../ui/Hits'; import type { HitsProps as HitsUiComponentProps } from '../ui/Hits'; import type { Hit, BaseHit } from 'instantsearch.js'; -import type { UseHitsProps } from 'react-instantsearch-hooks'; +import type { UseHitsProps } from 'react-instantsearch-core'; type UiProps = Pick< HitsUiComponentProps>, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/HitsPerPage.tsx b/packages/react-instantsearch/src/widgets/HitsPerPage.tsx similarity index 87% rename from packages/react-instantsearch-hooks-web/src/widgets/HitsPerPage.tsx rename to packages/react-instantsearch/src/widgets/HitsPerPage.tsx index 87ea1483cd..09df156c20 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/HitsPerPage.tsx +++ b/packages/react-instantsearch/src/widgets/HitsPerPage.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useHitsPerPage } from 'react-instantsearch-hooks'; +import { useHitsPerPage } from 'react-instantsearch-core'; import { HitsPerPage as HitsPerPageUiComponent } from '../ui/HitsPerPage'; import type { HitsPerPageProps as HitsPerPageUiComponentProps } from '../ui/HitsPerPage'; -import type { UseHitsPerPageProps } from 'react-instantsearch-hooks'; +import type { UseHitsPerPageProps } from 'react-instantsearch-core'; type UiProps = Pick< HitsPerPageUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/InfiniteHits.tsx b/packages/react-instantsearch/src/widgets/InfiniteHits.tsx similarity index 93% rename from packages/react-instantsearch-hooks-web/src/widgets/InfiniteHits.tsx rename to packages/react-instantsearch/src/widgets/InfiniteHits.tsx index 28552ab968..09a72a167e 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/InfiniteHits.tsx +++ b/packages/react-instantsearch/src/widgets/InfiniteHits.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import { useInfiniteHits } from 'react-instantsearch-hooks'; +import { useInfiniteHits } from 'react-instantsearch-core'; import { InfiniteHits as InfiniteHitsUiComponent } from '../ui/InfiniteHits'; import type { InfiniteHitsProps as InfiniteHitsUiComponentProps } from '../ui/InfiniteHits'; import type { BaseHit, Hit } from 'instantsearch.js'; -import type { UseInfiniteHitsProps } from 'react-instantsearch-hooks'; +import type { UseInfiniteHitsProps } from 'react-instantsearch-core'; type UiProps = Pick< InfiniteHitsUiComponentProps>, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Menu.tsx b/packages/react-instantsearch/src/widgets/Menu.tsx similarity index 91% rename from packages/react-instantsearch-hooks-web/src/widgets/Menu.tsx rename to packages/react-instantsearch/src/widgets/Menu.tsx index b0fa3e5aa1..70ddb15732 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/Menu.tsx +++ b/packages/react-instantsearch/src/widgets/Menu.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useMenu } from 'react-instantsearch-hooks'; +import { useMenu } from 'react-instantsearch-core'; import { Menu as MenuUiComponent } from '../ui/Menu'; import type { MenuProps as MenuUiComponentProps } from '../ui/Menu'; -import type { UseMenuProps } from 'react-instantsearch-hooks'; +import type { UseMenuProps } from 'react-instantsearch-core'; type UiProps = Pick< MenuUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Pagination.tsx b/packages/react-instantsearch/src/widgets/Pagination.tsx similarity index 93% rename from packages/react-instantsearch-hooks-web/src/widgets/Pagination.tsx rename to packages/react-instantsearch/src/widgets/Pagination.tsx index 69ada2fb2d..4c2a929c77 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/Pagination.tsx +++ b/packages/react-instantsearch/src/widgets/Pagination.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { usePagination } from 'react-instantsearch-hooks'; +import { usePagination } from 'react-instantsearch-core'; import { Pagination as PaginationUiComponent } from '../ui/Pagination'; import type { PaginationProps as PaginationUiComponentProps } from '../ui/Pagination'; -import type { UsePaginationProps } from 'react-instantsearch-hooks'; +import type { UsePaginationProps } from 'react-instantsearch-core'; type UiProps = Pick< PaginationUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/PoweredBy.tsx b/packages/react-instantsearch/src/widgets/PoweredBy.tsx similarity index 89% rename from packages/react-instantsearch-hooks-web/src/widgets/PoweredBy.tsx rename to packages/react-instantsearch/src/widgets/PoweredBy.tsx index 8ee62d5b49..544ba2e9d2 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/PoweredBy.tsx +++ b/packages/react-instantsearch/src/widgets/PoweredBy.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { usePoweredBy } from 'react-instantsearch-hooks'; +import { usePoweredBy } from 'react-instantsearch-core'; import { PoweredBy as PoweredByUiComponent } from '../ui/PoweredBy'; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/RangeInput.tsx b/packages/react-instantsearch/src/widgets/RangeInput.tsx similarity index 89% rename from packages/react-instantsearch-hooks-web/src/widgets/RangeInput.tsx rename to packages/react-instantsearch/src/widgets/RangeInput.tsx index 71c34e8c52..8e1e8e2bb5 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/RangeInput.tsx +++ b/packages/react-instantsearch/src/widgets/RangeInput.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useRange } from 'react-instantsearch-hooks'; +import { useRange } from 'react-instantsearch-core'; import { RangeInput as RangeInputUiComponent } from '../ui/RangeInput'; import type { RangeInputProps as RangeInputUiProps } from '../ui/RangeInput'; -import type { UseRangeProps } from 'react-instantsearch-hooks'; +import type { UseRangeProps } from 'react-instantsearch-core'; type UiProps = Pick< RangeInputUiProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/RefinementList.tsx b/packages/react-instantsearch/src/widgets/RefinementList.tsx similarity index 98% rename from packages/react-instantsearch-hooks-web/src/widgets/RefinementList.tsx rename to packages/react-instantsearch/src/widgets/RefinementList.tsx index 06d2a75e86..bcec125340 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/RefinementList.tsx +++ b/packages/react-instantsearch/src/widgets/RefinementList.tsx @@ -1,5 +1,5 @@ import React, { useRef, useState } from 'react'; -import { useRefinementList } from 'react-instantsearch-hooks'; +import { useRefinementList } from 'react-instantsearch-core'; import { RefinementList as RefinementListUiComponent } from '../ui/RefinementList'; import { SearchBox as SearchBoxUiComponent } from '../ui/SearchBox'; @@ -8,7 +8,7 @@ import type { RefinementListProps as RefinementListUiComponentProps } from '../u import type { SearchBoxTranslations } from '../ui/SearchBox'; import type { RefinementListItem } from 'instantsearch.js/es/connectors/refinement-list/connectRefinementList'; import type { RefinementListWidgetParams } from 'instantsearch.js/es/widgets/refinement-list/refinement-list'; -import type { UseRefinementListProps } from 'react-instantsearch-hooks'; +import type { UseRefinementListProps } from 'react-instantsearch-core'; type UiProps = Pick< RefinementListUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/SearchBox.tsx b/packages/react-instantsearch/src/widgets/SearchBox.tsx similarity index 94% rename from packages/react-instantsearch-hooks-web/src/widgets/SearchBox.tsx rename to packages/react-instantsearch/src/widgets/SearchBox.tsx index bdf70fe44a..c5e950a953 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/SearchBox.tsx +++ b/packages/react-instantsearch/src/widgets/SearchBox.tsx @@ -1,10 +1,10 @@ import React, { useRef, useState } from 'react'; -import { useSearchBox } from 'react-instantsearch-hooks'; +import { useSearchBox } from 'react-instantsearch-core'; import { SearchBox as SearchBoxUiComponent } from '../ui/SearchBox'; import type { SearchBoxProps as SearchBoxUiComponentProps } from '../ui/SearchBox'; -import type { UseSearchBoxProps } from 'react-instantsearch-hooks'; +import type { UseSearchBoxProps } from 'react-instantsearch-core'; type UiProps = Pick< SearchBoxUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Snippet.tsx b/packages/react-instantsearch/src/widgets/Snippet.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/Snippet.tsx rename to packages/react-instantsearch/src/widgets/Snippet.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/SortBy.tsx b/packages/react-instantsearch/src/widgets/SortBy.tsx similarity index 85% rename from packages/react-instantsearch-hooks-web/src/widgets/SortBy.tsx rename to packages/react-instantsearch/src/widgets/SortBy.tsx index aa2648a129..75c0fc3d41 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/SortBy.tsx +++ b/packages/react-instantsearch/src/widgets/SortBy.tsx @@ -1,10 +1,10 @@ import React from 'react'; -import { useSortBy } from 'react-instantsearch-hooks'; +import { useSortBy } from 'react-instantsearch-core'; import { SortBy as SortByUiComponent } from '../ui/SortBy'; import type { SortByProps as SortByUiComponentProps } from '../ui/SortBy'; -import type { UseSortByProps } from 'react-instantsearch-hooks'; +import type { UseSortByProps } from 'react-instantsearch-core'; type UiProps = Pick; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/Stats.tsx b/packages/react-instantsearch/src/widgets/Stats.tsx similarity index 91% rename from packages/react-instantsearch-hooks-web/src/widgets/Stats.tsx rename to packages/react-instantsearch/src/widgets/Stats.tsx index caa8619e2e..384a83fdd6 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/Stats.tsx +++ b/packages/react-instantsearch/src/widgets/Stats.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { useStats } from 'react-instantsearch-hooks'; +import { useStats } from 'react-instantsearch-core'; import { Stats as StatsUiComponent } from '../ui/Stats'; @@ -7,7 +7,7 @@ import type { StatsProps as StatsUiComponentProps, StatsTranslationOptions, } from '../ui/Stats'; -import type { UseStatsProps } from 'react-instantsearch-hooks'; +import type { UseStatsProps } from 'react-instantsearch-core'; type UiProps = Pick< StatsUiComponentProps, diff --git a/packages/react-instantsearch-hooks-web/src/widgets/ToggleRefinement.tsx b/packages/react-instantsearch/src/widgets/ToggleRefinement.tsx similarity index 93% rename from packages/react-instantsearch-hooks-web/src/widgets/ToggleRefinement.tsx rename to packages/react-instantsearch/src/widgets/ToggleRefinement.tsx index 7ad0d8c242..33898121c1 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/ToggleRefinement.tsx +++ b/packages/react-instantsearch/src/widgets/ToggleRefinement.tsx @@ -1,11 +1,11 @@ import React from 'react'; -import { useToggleRefinement } from 'react-instantsearch-hooks'; +import { useToggleRefinement } from 'react-instantsearch-core'; import { ToggleRefinement as ToggleRefinementUiComponent } from '../ui/ToggleRefinement'; import type { PartialKeys } from '../types'; import type { ToggleRefinementProps as ToggleRefinementUiComponentProps } from '../ui/ToggleRefinement'; -import type { UseToggleRefinementProps } from 'react-instantsearch-hooks'; +import type { UseToggleRefinementProps } from 'react-instantsearch-core'; type UiProps = Pick; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Breadcrumb.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Breadcrumb.test.tsx similarity index 86% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Breadcrumb.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Breadcrumb.test.tsx index fdea8fe02f..54d0ac7a54 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Breadcrumb.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/Breadcrumb.test.tsx @@ -7,14 +7,14 @@ import { createSearchClient, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import React from 'react'; -import { useHierarchicalMenu } from 'react-instantsearch-hooks'; +import { useHierarchicalMenu } from 'react-instantsearch-core'; import { Breadcrumb } from '../Breadcrumb'; -import type { UseHierarchicalMenuProps } from 'react-instantsearch-hooks'; +import type { UseHierarchicalMenuProps } from 'react-instantsearch-core'; describe('Breadcrumb', () => { const hierarchicalFacets = { @@ -46,7 +46,7 @@ describe('Breadcrumb', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + { title="Some custom title" attributes={hierarchicalAttributes} /> - + ); const root = container.firstChild; @@ -65,13 +65,13 @@ describe('Breadcrumb', () => { test('renders with translations', async () => { const searchClient = createMockedSearchClient(); const { getByRole } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/ClearRefinements.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/ClearRefinements.test.tsx similarity index 93% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/ClearRefinements.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/ClearRefinements.test.tsx index 0483a464eb..5fa9421c0a 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/ClearRefinements.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/ClearRefinements.test.tsx @@ -3,27 +3,27 @@ */ import { createSearchClient } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; import { useCurrentRefinements, useRefinementList, -} from 'react-instantsearch-hooks'; +} from 'react-instantsearch-core'; import { ClearRefinements } from '../ClearRefinements'; import type { UseRefinementListProps, UseCurrentRefinementsProps, -} from 'react-instantsearch-hooks'; +} from 'react-instantsearch-core'; describe('ClearRefinements', () => { test('renders with default props', async () => { const searchClient = createSearchClient({}); const { container } = render( - { > - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -58,9 +58,9 @@ describe('ClearRefinements', () => { test('renders with a disabled button when there are no refinements', async () => { const searchClient = createSearchClient({}); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -88,7 +88,7 @@ describe('ClearRefinements', () => { test('clears all refinements', async () => { const searchClient = createSearchClient({}); const { container, queryAllByRole } = render( - { - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -160,7 +160,7 @@ describe('ClearRefinements', () => { test('inclusively restricts what refinements to clear', async () => { const searchClient = createSearchClient({}); const { container, queryAllByRole } = render( - { - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -254,7 +254,7 @@ describe('ClearRefinements', () => { test('exclusively restricts what refinements to clear', async () => { const searchClient = createSearchClient({}); const { container, queryAllByRole } = render( - { - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -348,7 +348,7 @@ describe('ClearRefinements', () => { test('restricts what refinements to clear with custom logic', async () => { const searchClient = createSearchClient({}); const { container, queryAllByRole } = render( - { items.filter((item) => item !== 'brand')} /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -443,13 +443,13 @@ describe('ClearRefinements', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; @@ -460,7 +460,7 @@ describe('ClearRefinements', () => { test('renders with translations', async () => { const searchClient = createSearchClient({}); const { getByRole } = render( - { > - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/CurrentRefinements.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/CurrentRefinements.test.tsx similarity index 95% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/CurrentRefinements.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/CurrentRefinements.test.tsx index 568c350957..9cd8c1355e 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/CurrentRefinements.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/CurrentRefinements.test.tsx @@ -3,20 +3,20 @@ */ import { createSearchClient } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { useRefinementList } from 'react-instantsearch-hooks'; +import { useRefinementList } from 'react-instantsearch-core'; import { CurrentRefinements } from '../CurrentRefinements'; -import type { UseRefinementListProps } from 'react-instantsearch-hooks'; +import type { UseRefinementListProps } from 'react-instantsearch-core'; describe('CurrentRefinements', () => { test('renders with default props', async () => { const { container } = render( - { - + ); await waitFor(() => { @@ -123,9 +123,9 @@ describe('CurrentRefinements', () => { test('renders with a specific set of class names when there are no refinements', async () => { const searchClient = createSearchClient({}); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -145,7 +145,7 @@ describe('CurrentRefinements', () => { test('clears a refinement', async () => { const { container, queryByText } = render( - { - + ); await waitFor(() => { @@ -304,7 +304,7 @@ describe('CurrentRefinements', () => { render(
    - { > - +
    ); @@ -334,7 +334,7 @@ describe('CurrentRefinements', () => { test('does not clear when pressing a modifier key', async () => { const searchClient = createSearchClient({}); const { container } = render( - { > - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -450,7 +450,7 @@ describe('CurrentRefinements', () => { test('inclusively restricts what refinements to display', async () => { const searchClient = createSearchClient({}); const { container, queryByText } = render( - { - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -513,7 +513,7 @@ describe('CurrentRefinements', () => { test('exclusively restricts what refinements to display', async () => { const searchClient = createSearchClient({}); const { container, queryByText } = render( - { - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -576,7 +576,7 @@ describe('CurrentRefinements', () => { test('restricts what refinements to display with custom logic', async () => { const searchClient = createSearchClient({}); const { container, queryByText } = render( - { items.filter((item) => item.attribute !== 'brand') } /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -642,13 +642,13 @@ describe('CurrentRefinements', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/HierarchicalMenu.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/HierarchicalMenu.test.tsx similarity index 91% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/HierarchicalMenu.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/HierarchicalMenu.test.tsx index 2152dc4617..15e33f4c8d 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/HierarchicalMenu.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/HierarchicalMenu.test.tsx @@ -7,7 +7,7 @@ import { createSearchClient, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -49,9 +49,9 @@ describe('HierarchicalMenu', () => { test('renders with props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -164,9 +164,9 @@ describe('HierarchicalMenu', () => { test('limits the number of items to display', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -211,14 +211,14 @@ describe('HierarchicalMenu', () => { test('transforms the items', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + items.map((item) => ({ ...item, label: item.label.toUpperCase() })) } /> - + ); await waitFor(() => { @@ -238,9 +238,9 @@ describe('HierarchicalMenu', () => { test('sorts the items by ascending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -259,9 +259,9 @@ describe('HierarchicalMenu', () => { test('sorts the items by descending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -280,9 +280,9 @@ describe('HierarchicalMenu', () => { test('sorts the items by count', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -297,7 +297,7 @@ describe('HierarchicalMenu', () => { test('sorts the items by refinement state', async () => { const searchClient = createMockedSearchClient(); const { container, findByText } = render( - + { })) } /> - + ); await waitFor(() => @@ -355,12 +355,12 @@ describe('HierarchicalMenu', () => { test('sorts the items using a sorting function', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + b.name.localeCompare(a.name)} /> - + ); await waitFor(() => @@ -381,9 +381,9 @@ describe('HierarchicalMenu', () => { test('displays a "Show more" button', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -447,14 +447,14 @@ describe('HierarchicalMenu', () => { test('limits the number of items to reveal', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -482,14 +482,14 @@ describe('HierarchicalMenu', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const root = container.firstChild; @@ -500,7 +500,7 @@ describe('HierarchicalMenu', () => { test('renders with translations', async () => { const searchClient = createMockedSearchClient(); const { getByRole } = render( - + { }} showMore /> - + ); await waitFor(() => { diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Highlight.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Highlight.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Highlight.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Highlight.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Hits.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Hits.test.tsx similarity index 90% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Hits.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Hits.test.tsx index 266494a7ad..8ed42a3a43 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Hits.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/Hits.test.tsx @@ -7,7 +7,7 @@ import { createMultiSearchResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import React from 'react'; @@ -19,9 +19,9 @@ import type { AlgoliaHit } from 'instantsearch.js'; describe('Hits', () => { test('renders with default props', async () => { const { container } = render( - + - + ); await waitFor(() => { @@ -63,13 +63,13 @@ describe('Hits', () => { }); const { container } = render( - + hitComponent={({ hit }) => ( {`${hit.__position} - ${hit.somethingSpecial}`} )} /> - + ); await waitFor(() => { @@ -110,13 +110,13 @@ describe('Hits', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/HitsPerPage.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/HitsPerPage.test.tsx similarity index 89% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/HitsPerPage.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/HitsPerPage.test.tsx index 2e0a98d477..3fd49d863a 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/HitsPerPage.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/HitsPerPage.test.tsx @@ -3,7 +3,7 @@ */ import { createSearchClient } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -14,7 +14,7 @@ describe('HitsPerPage', () => { test('renders with props', async () => { const searchClient = createSearchClient({}); const { container } = render( - + { { label: '30', value: 30 }, ]} /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -62,7 +62,7 @@ describe('HitsPerPage', () => { test('selects current value', async () => { const searchClient = createSearchClient({}); const { getByRole } = render( - { { label: '30', value: 30 }, ]} /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -96,7 +96,7 @@ describe('HitsPerPage', () => { test('refines on select', async () => { const searchClient = createSearchClient({}); const { getByRole } = render( - + { { label: '30', value: 30 }, ]} /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -125,7 +125,7 @@ describe('HitsPerPage', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + { { label: '30', value: 30 }, ]} /> - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/InfiniteHits.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/InfiniteHits.test.tsx similarity index 92% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/InfiniteHits.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/InfiniteHits.test.tsx index 86a45bad2c..aee95a6ae1 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/InfiniteHits.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/InfiniteHits.test.tsx @@ -7,7 +7,7 @@ import { createMultiSearchResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { act, render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -57,9 +57,9 @@ describe('InfiniteHits', () => { test('renders with default props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -124,13 +124,13 @@ describe('InfiniteHits', () => { test('renders with a custom hit component', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + hitComponent={({ hit }) => ( {`${hit.__position} - ${hit.somethingSpecial}`} )} /> - + ); await waitFor(() => @@ -184,13 +184,13 @@ describe('InfiniteHits', () => { test('displays more hits when clicking the "Show More" button', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + ( {__position} )} /> - + ); await waitFor(() => @@ -237,7 +237,7 @@ describe('InfiniteHits', () => { test('displays previous hits when clicking the "Show Previous" button', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - @@ -246,7 +246,7 @@ describe('InfiniteHits', () => { {__position} )} /> - + ); await waitFor(() => @@ -295,9 +295,9 @@ describe('InfiniteHits', () => { test('hides the "Show Previous" button when `showPrevious` is `false`', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -327,9 +327,9 @@ describe('InfiniteHits', () => { test('marks the "Show Previous" button as disabled on first page', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -353,12 +353,12 @@ describe('InfiniteHits', () => { test('marks the "Show More" button as disabled on last page', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -378,13 +378,13 @@ describe('InfiniteHits', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const root = container.firstChild; @@ -395,7 +395,7 @@ describe('InfiniteHits', () => { test('renders with translations', async () => { const searchClient = createMockedSearchClient(); const { getByRole } = render( - @@ -405,7 +405,7 @@ describe('InfiniteHits', () => { showPreviousButtonText: 'Display previous', }} /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Menu.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Menu.test.tsx similarity index 94% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Menu.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Menu.test.tsx index 1321e8d82b..f9e19610c6 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Menu.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/Menu.test.tsx @@ -7,7 +7,7 @@ import { createAlgoliaSearchClient, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -66,9 +66,9 @@ describe('Menu', () => { test('renders with props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -305,9 +305,9 @@ describe('Menu', () => { test('limits the number of items to display', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -426,7 +426,7 @@ describe('Menu', () => { test('transforms the items', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + @@ -436,7 +436,7 @@ describe('Menu', () => { })) } /> - + ); await waitFor(() => { @@ -463,9 +463,9 @@ describe('Menu', () => { test('sorts the items by ascending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -491,9 +491,9 @@ describe('Menu', () => { test('sorts the items by descending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -519,9 +519,9 @@ describe('Menu', () => { test('sorts the items by count', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -547,7 +547,7 @@ describe('Menu', () => { test('sorts the items by refinement state', async () => { const searchClient = createMockedSearchClient(); const { container, findByText } = render( - + { })) } /> - + ); await waitFor(() => { @@ -626,12 +626,12 @@ describe('Menu', () => { test('sorts the items using a sorting function', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + b.name.localeCompare(a.name)} /> - + ); await waitFor(() => { @@ -659,9 +659,9 @@ describe('Menu', () => { test('displays a "Show more" button', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -892,9 +892,9 @@ describe('Menu', () => { test('limits the number of items to reveal', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -919,14 +919,14 @@ describe('Menu', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const root = container.firstChild; @@ -937,7 +937,7 @@ describe('Menu', () => { test('renders with translations', async () => { const searchClient = createMockedSearchClient(); const { getByRole } = render( - + { }} showMore /> - + ); await waitFor(() => { diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Pagination.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Pagination.test.tsx similarity index 97% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Pagination.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Pagination.test.tsx index cf4b4c77a4..bc8a1ef3b6 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Pagination.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/Pagination.test.tsx @@ -7,7 +7,7 @@ import { createAlgoliaSearchClient, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -41,9 +41,9 @@ function createMockedSearchClient({ nbPages }: { nbPages?: number } = {}) { describe('Pagination', () => { test('renders with default props', async () => { const { container } = render( - + - + ); await waitFor(() => @@ -120,9 +120,9 @@ describe('Pagination', () => { test('renders with props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -282,9 +282,9 @@ describe('Pagination', () => { test('navigates between pages', async () => { const searchClient = createMockedSearchClient(); const { container, getByText } = render( - + - + ); await waitFor(() => @@ -1219,9 +1219,9 @@ describe('Pagination', () => { test('does not navigate when pressing a modifier key', async () => { const searchClient = createMockedSearchClient(); const { getByText } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -1288,9 +1288,9 @@ describe('Pagination', () => { test('adds items around the current one', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -1473,9 +1473,9 @@ describe('Pagination', () => { }); const { container } = render( - + - + ); await waitFor(() => @@ -1609,9 +1609,9 @@ describe('Pagination', () => { test('limits the total pages to display', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -1722,9 +1722,9 @@ describe('Pagination', () => { test('hides the "First" item when `showFirst` is `false`', async () => { const { container } = render( - + - + ); await waitFor(() => @@ -1795,9 +1795,9 @@ describe('Pagination', () => { test('hides the "Previous" item when `showPrevious` is `false`', async () => { const { container } = render( - + - + ); await waitFor(() => @@ -1868,9 +1868,9 @@ describe('Pagination', () => { test('hides the "Next" item when `showNext` is `false`', async () => { const { container } = render( - + - + ); await waitFor(() => @@ -1939,9 +1939,9 @@ describe('Pagination', () => { test('hides the "Last" item when `showLast` is `false`', async () => { const { container } = render( - + - + ); await waitFor(() => @@ -2010,13 +2010,13 @@ describe('Pagination', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; @@ -2026,7 +2026,7 @@ describe('Pagination', () => { test('renders with translations', async () => { const { getByRole, findByRole, debug } = render( - { `#${currentPage}/${nbPages}`, }} /> - + ); await waitFor(() => diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/PoweredBy.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/PoweredBy.test.tsx similarity index 96% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/PoweredBy.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/PoweredBy.test.tsx index b520446142..16eb41badf 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/PoweredBy.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/PoweredBy.test.tsx @@ -2,7 +2,7 @@ * @jest-environment jsdom */ -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render } from '@testing-library/react'; import React from 'react'; @@ -11,9 +11,9 @@ import { PoweredBy } from '../PoweredBy'; describe('PoweredBy', () => { test('renders with default props', () => { const { container } = render( - + - + ); expect(container).toMatchInlineSnapshot(` @@ -49,9 +49,9 @@ describe('PoweredBy', () => { test('renders for dark themes', () => { const { container } = render( - + - + ); expect(container.firstChild).toHaveClass('ais-PoweredBy--dark'); @@ -88,7 +88,7 @@ describe('PoweredBy', () => { test('customizes the class names with the light theme', () => { const { container } = render( - + { logo: 'MyCustomPoweredByLogo', }} /> - + ); expect(container.firstChild).toHaveClass( @@ -116,7 +116,7 @@ describe('PoweredBy', () => { test('customizes the class names with the dark theme', () => { const { container } = render( - + { logo: 'MyCustomPoweredByLogo', }} /> - + ); expect(container.firstChild).toHaveClass( @@ -145,13 +145,13 @@ describe('PoweredBy', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/RangeInput.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/RangeInput.test.tsx similarity index 89% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/RangeInput.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/RangeInput.test.tsx index 1c4f9846d8..76aa12521c 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/RangeInput.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/RangeInput.test.tsx @@ -7,7 +7,7 @@ import { createSearchClient, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -44,9 +44,9 @@ describe('RangeInput', () => { test('renders with default props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -107,7 +107,7 @@ describe('RangeInput', () => { test('renders with initial refinements', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - { }} > - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -134,9 +134,9 @@ describe('RangeInput', () => { test('renders with precision', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -151,9 +151,9 @@ describe('RangeInput', () => { test('refines on submit', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -187,14 +187,14 @@ describe('RangeInput', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const root = container.firstChild; @@ -205,7 +205,7 @@ describe('RangeInput', () => { test('renders with translations', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + { submitButtonText: 'Send', }} /> - + ); await waitFor(() => { diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/RefinementList.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx similarity index 95% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/RefinementList.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx index 98dc06f5be..d67fb3267d 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/RefinementList.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/RefinementList.test.tsx @@ -8,7 +8,7 @@ import { createSFFVResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -119,9 +119,9 @@ describe('RefinementList', () => { test('renders with props', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -403,9 +403,9 @@ describe('RefinementList', () => { test('enables conjunctive faceting', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -439,9 +439,9 @@ describe('RefinementList', () => { test('limits the number of items to display', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -582,7 +582,7 @@ describe('RefinementList', () => { test('transforms the items', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + @@ -592,7 +592,7 @@ describe('RefinementList', () => { })) } /> - + ); await waitFor(() => { @@ -619,9 +619,9 @@ describe('RefinementList', () => { test('sorts the items by ascending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -647,9 +647,9 @@ describe('RefinementList', () => { test('sorts the items by descending name', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -675,9 +675,9 @@ describe('RefinementList', () => { test('sorts the items by count', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -703,9 +703,9 @@ describe('RefinementList', () => { test('sorts the items by refinement state', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -759,12 +759,12 @@ describe('RefinementList', () => { test('sorts the items using a sorting function', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + a.name.length - b.name.length} /> - + ); await waitFor(() => { @@ -792,13 +792,13 @@ describe('RefinementList', () => { test('displays a search box', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const searchInput = container.querySelector( @@ -881,13 +881,13 @@ describe('RefinementList', () => { ), }); const { container } = render( - + - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); @@ -1027,9 +1027,9 @@ describe('RefinementList', () => { test('displays a "Show more" button', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -1305,13 +1305,13 @@ describe('RefinementList', () => { test('limits the number of items to reveal', async () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => @@ -1344,14 +1344,14 @@ describe('RefinementList', () => { test('forwards custom class names and `div` props to the root element', () => { const searchClient = createMockedSearchClient(); const { container } = render( - + - + ); const root = container.firstChild; @@ -1376,7 +1376,7 @@ describe('RefinementList', () => { ), }); const { container, getByRole } = render( - + { }} searchable /> - + ); await waitFor(() => expect(searchClient.search).toHaveBeenCalledTimes(1)); diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/SearchBox.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/SearchBox.test.tsx similarity index 91% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/SearchBox.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/SearchBox.test.tsx index 9c845cd302..0bc0569d65 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/SearchBox.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/SearchBox.test.tsx @@ -2,7 +2,7 @@ * @jest-environment jsdom */ -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { act, render, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -14,9 +14,9 @@ import type { InstantSearch, UiState } from 'instantsearch.js'; describe('SearchBox', () => { test('renders with default props', async () => { const { container } = render( - + - + ); await waitFor(() => { @@ -126,9 +126,9 @@ describe('SearchBox', () => { test('forwards placeholder prop', async () => { const { container } = render( - + - + ); await waitFor(() => { @@ -141,9 +141,9 @@ describe('SearchBox', () => { test('forwards `autoFocus` prop', async () => { const { container } = render( - + - + ); await waitFor(() => { @@ -155,7 +155,7 @@ describe('SearchBox', () => { let lastUiState: UiState = {}; const { container } = render( - { }} > - + ); const input = container.querySelector( @@ -194,7 +194,7 @@ describe('SearchBox', () => { let lastUiState: UiState = {}; const { container } = render( - { }} > - + ); const resetButton = container.querySelector( @@ -232,13 +232,13 @@ describe('SearchBox', () => { let localSetUiState: InstantSearch['setUiState']; const { container } = render( - { localSetUiState = setUiState; }} > - + ); const input = container.querySelector( '.ais-SearchBox-input' @@ -262,13 +262,13 @@ describe('SearchBox', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; @@ -280,13 +280,13 @@ describe('SearchBox', () => { let lastUiState: UiState = {}; const { container } = render( - { lastUiState = uiState; }} > - + ); const input = container.querySelector( @@ -305,13 +305,13 @@ describe('SearchBox', () => { let lastUiState: UiState = {}; const { container } = render( - { lastUiState = uiState; }} > - + ); const input = container.querySelector( @@ -329,13 +329,13 @@ describe('SearchBox', () => { let lastUiState: UiState = {}; const { container } = render( - { lastUiState = uiState; }} > - + ); const input = container.querySelector( @@ -354,14 +354,14 @@ describe('SearchBox', () => { test('renders with translations', () => { const { getByRole } = render( - + - + ); expect(getByRole('button', { name: 'Submit' })).toBeInTheDocument(); diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Snippet.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Snippet.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Snippet.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Snippet.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/SortBy.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/SortBy.test.tsx similarity index 92% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/SortBy.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/SortBy.test.tsx index 98c1db36ce..db72cc07c1 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/SortBy.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/SortBy.test.tsx @@ -3,7 +3,7 @@ */ import { createSearchClient } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -13,7 +13,7 @@ import { SortBy } from '../SortBy'; describe('SortBy', () => { test('renders with props', () => { const { container } = render( - + { { label: 'Price (desc)', value: 'instant_search_price_desc' }, ]} /> - + ); expect(document.querySelector('.ais-SortBy-select')).toHaveValue( @@ -62,7 +62,7 @@ describe('SortBy', () => { test('transform the passed items', () => { const { container } = render( - + items.map((item) => ({ @@ -76,7 +76,7 @@ describe('SortBy', () => { { label: 'Price (desc)', value: 'instant_search_price_desc' }, ]} /> - + ); expect(container).toMatchInlineSnapshot(` @@ -115,7 +115,7 @@ describe('SortBy', () => { const client = createSearchClient({}); const { getByRole } = render( - @@ -126,7 +126,7 @@ describe('SortBy', () => { { label: 'Price (desc)', value: 'instant_search_price_desc' }, ]} /> - + ); await waitFor(() => { @@ -156,7 +156,7 @@ describe('SortBy', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + { { label: 'Price (desc)', value: 'instant_search_price_desc' }, ]} /> - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Stats.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/Stats.test.tsx similarity index 86% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/Stats.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/Stats.test.tsx index ee0f446729..a3fa98c792 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/Stats.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/Stats.test.tsx @@ -7,7 +7,7 @@ import { createMultiSearchResponse, createSingleSearchResponse, } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import React from 'react'; @@ -36,9 +36,9 @@ function createMockedSearchClient({ nbSorted }: { nbSorted?: number } = {}) { describe('Stats', () => { test('renders with default props', async () => { const { container } = render( - + - + ); await waitFor(() => { @@ -59,9 +59,9 @@ describe('Stats', () => { test('renders with proper message nbHits and processingTimeMS', async () => { const client = createMockedSearchClient(); const { container } = render( - + - + ); await waitFor(() => { @@ -86,9 +86,9 @@ describe('Stats', () => { test('renders with proper message when hits are sorted', async () => { const client = createMockedSearchClient({ nbSorted: 500 }); const { container } = render( - + - + ); await waitFor(() => { @@ -113,9 +113,9 @@ describe('Stats', () => { test('renders with proper message when nbSorted equals nbHits', async () => { const client = createMockedSearchClient({ nbSorted: 1000 }); const { container } = render( - + - + ); await waitFor(() => { @@ -140,13 +140,13 @@ describe('Stats', () => { test('renders with translations', async () => { const client = createMockedSearchClient(); const { container } = render( - + 'Nice stats', }} /> - + ); await waitFor(() => { @@ -170,13 +170,13 @@ describe('Stats', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/ToggleRefinement.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/ToggleRefinement.test.tsx similarity index 89% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/ToggleRefinement.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/ToggleRefinement.test.tsx index e58660ea64..73aef78a29 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/ToggleRefinement.test.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/ToggleRefinement.test.tsx @@ -3,7 +3,7 @@ */ import { createSearchClient } from '@instantsearch/mocks'; -import { InstantSearchHooksTestWrapper } from '@instantsearch/testutils'; +import { InstantSearchTestWrapper } from '@instantsearch/testutils'; import { render, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; @@ -13,9 +13,9 @@ import { ToggleRefinement } from '../ToggleRefinement'; describe('ToggleRefinement', () => { test('renders with props', () => { const { container } = render( - + - + ); expect(container).toMatchInlineSnapshot(` @@ -43,9 +43,9 @@ describe('ToggleRefinement', () => { test('customizes the label', () => { const { container } = render( - + - + ); expect( @@ -55,7 +55,7 @@ describe('ToggleRefinement', () => { test('renders checked when the attribute is refined', () => { const { container } = render( - { }} > - + ); expect( @@ -79,9 +79,9 @@ describe('ToggleRefinement', () => { const client = createSearchClient({}); const { container } = render( - + - + ); await waitFor(() => { @@ -134,9 +134,9 @@ describe('ToggleRefinement', () => { const client = createSearchClient({}); const { container } = render( - + - + ); await waitFor(() => { @@ -184,14 +184,14 @@ describe('ToggleRefinement', () => { test('forwards custom class names and `div` props to the root element', () => { const { container } = render( - + - + ); const root = container.firstChild; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/__utils__/all-widgets.tsx b/packages/react-instantsearch/src/widgets/__tests__/__utils__/all-widgets.tsx similarity index 99% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/__utils__/all-widgets.tsx rename to packages/react-instantsearch/src/widgets/__tests__/__utils__/all-widgets.tsx index 5b1192088a..84937dc069 100644 --- a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/__utils__/all-widgets.tsx +++ b/packages/react-instantsearch/src/widgets/__tests__/__utils__/all-widgets.tsx @@ -4,7 +4,7 @@ import { renderToString } from 'react-dom/server'; import { InstantSearch, InstantSearchServerContext, -} from 'react-instantsearch-hooks'; +} from 'react-instantsearch-core'; import * as widgets from '../..'; diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/all-components.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/all-components.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/all-components.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/all-components.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/__tests__/all-widgets.test.tsx b/packages/react-instantsearch/src/widgets/__tests__/all-widgets.test.tsx similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/__tests__/all-widgets.test.tsx rename to packages/react-instantsearch/src/widgets/__tests__/all-widgets.test.tsx diff --git a/packages/react-instantsearch-hooks-web/src/widgets/index.ts b/packages/react-instantsearch/src/widgets/index.ts similarity index 100% rename from packages/react-instantsearch-hooks-web/src/widgets/index.ts rename to packages/react-instantsearch/src/widgets/index.ts diff --git a/packages/react-instantsearch/test/module/is-cjs-module.cjs b/packages/react-instantsearch/test/module/is-cjs-module.cjs new file mode 100644 index 0000000000..b9de53a706 --- /dev/null +++ b/packages/react-instantsearch/test/module/is-cjs-module.cjs @@ -0,0 +1,9 @@ +/* eslint-disable no-console */ + +const assert = require('assert'); + +const ReactInstantSearch = require('react-instantsearch'); + +assert.ok(ReactInstantSearch); + +console.log('react-instantsearch is valid CJS'); diff --git a/packages/react-instantsearch/test/module/is-es-module.mjs b/packages/react-instantsearch/test/module/is-es-module.mjs new file mode 100644 index 0000000000..17e7902299 --- /dev/null +++ b/packages/react-instantsearch/test/module/is-es-module.mjs @@ -0,0 +1,8 @@ +/* eslint-disable no-console */ +import assert from 'assert'; + +import * as ReactInstantSearch from 'react-instantsearch'; + +assert.ok(ReactInstantSearch); + +console.log('react-instantsearch is valid ESM'); diff --git a/packages/react-instantsearch-hooks-web/tsconfig.declaration.json b/packages/react-instantsearch/tsconfig.declaration.json similarity index 100% rename from packages/react-instantsearch-hooks-web/tsconfig.declaration.json rename to packages/react-instantsearch/tsconfig.declaration.json diff --git a/scripts/website/README.md b/scripts/website/README.md deleted file mode 100644 index 0d06faad92..0000000000 --- a/scripts/website/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# React InstantSearch website builder - -The examples of React InstantSearch are built using this webpack configuration, unlike the other examples for netlify which are built using their own (parcel) configuration. diff --git a/scripts/website/package.json b/scripts/website/package.json deleted file mode 100644 index 4e9dfffaa3..0000000000 --- a/scripts/website/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "example-react-instantsearch-builder", - "private": true, - "version": "1.0.1", - "license": "MIT", - "scripts": { - "website:examples": "webpack --config webpack.config.js" - }, - "dependencies": { - "babel-loader": "^8.2.2", - "copy-webpack-plugin": "^5.0.4", - "css-loader": "^3.2.0", - "file-loader": "^4.2.0", - "glob": "^7.1.4", - "html-webpack-plugin": "^3.2.0", - "null-loader": "^3.0.0", - "style-loader": "^1.0.0", - "webpack": "^4.41.5", - "webpack-cli": "^3.3.7" - } -} diff --git a/scripts/website/webpack.config.js b/scripts/website/webpack.config.js deleted file mode 100644 index 654e82e125..0000000000 --- a/scripts/website/webpack.config.js +++ /dev/null @@ -1,102 +0,0 @@ -const path = require('path'); -const glob = require('glob'); -const HTMLWebpackPlugin = require('html-webpack-plugin'); -const CopyWebpackPlugin = require('copy-webpack-plugin'); - -const names = ['default-theme', 'e-commerce', 'media', 'tourism']; - -const outputPath = path.join(__dirname, '..', '..', 'website'); -const examples = glob.sync( - path.join('examples', 'react', `@(${names.join('|')})`), - { - cwd: path.join(__dirname, '..', '..'), - } -); - -module.exports = { - mode: 'production', - entry: Object.fromEntries( - examples.map((example) => [ - example, - path.join(__dirname, '..', '..', example, 'index.js'), - ]) - ), - output: { - filename: '[name]/index.[chunkhash].js', - publicPath: '/', - path: outputPath, - }, - resolve: { - alias: { - 'react-instantsearch-dom': path.resolve( - __dirname, - '../../packages/react-instantsearch-dom' - ), - 'react-instantsearch-dom-maps': path.resolve( - __dirname, - '../../packages/react-instantsearch-dom-maps' - ), - }, - }, - module: { - rules: [ - { - test: /\.(js|ts|tsx)$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - options: { - rootMode: 'upward', - envName: 'webpack', - }, - }, - ], - }, - { - test: /\.css$/, - use: [{ loader: 'style-loader' }, { loader: 'css-loader' }], - }, - { - test: /\.(png|svg|jpg|gif)$/, - use: [ - { - loader: 'file-loader', - options: { - publicPath: (filename, absolutePath, context) => - `/${path.relative(context, absolutePath)}`, - context: path.join(__dirname, '..', '..'), - outputPath(_url, resourcePath, context) { - return path.relative(context, resourcePath); - }, - name: '[name].[ext]', - }, - }, - ], - }, - ], - }, - performance: { - hints: false, - }, - plugins: [ - ...examples.map( - (example) => - new HTMLWebpackPlugin({ - template: path.join(__dirname, '..', '..', example, 'index.html'), - filename: path.join(outputPath, example, 'index.html'), - chunks: [example], - }) - ), - new CopyWebpackPlugin([ - ...examples.map((example) => ({ - from: path.join(__dirname, '..', '..', example, 'assets'), - to: path.join(outputPath, example, 'assets'), - })), - { - from: path.join(__dirname, '..', '..', 'assets'), - to: 'assets/', - }, - ]), - ], -}; diff --git a/tests/common/README.md b/tests/common/README.md index eed97f5d84..dd1f04b3ab 100644 --- a/tests/common/README.md +++ b/tests/common/README.md @@ -18,8 +18,8 @@ Tests that only apply to specific flavors belong to their relevant packages, as - [Common scenarios](../../tests/common/widgets/breadcrumb) - Flavor-specific tests: - - [InstantSearch.js](../../packages/instantsearch.js/src/widgets/breadcrumb) - - [React InstantSearch Hooks](../../packages/react-instantsearch-hooks-web/src/widgets/__tests__) + - [InstantSearch.js](../../packages/instantsearch.js/src/widgets/breadcrumb/__tests__) + - [React InstantSearch](../../packages/react-instantsearch/src/widgets/__tests__) - [Vue InstantSearch](../../packages/vue-instantsearch/src/components/__tests__) > **Note** Flavor-specific tests should be the exception. They should either cover inconsistencies between flavors that should go away in a next major, or assert flavor-specific behavior or APIs. diff --git a/tests/e2e/flavors.js b/tests/e2e/flavors.js index 6c6875111c..4c33cc5800 100644 --- a/tests/e2e/flavors.js +++ b/tests/e2e/flavors.js @@ -1,3 +1,3 @@ module.exports = { - flavors: ['js', 'js-umd', 'react', 'react-hooks', 'vue'], + flavors: ['js', 'js-umd', 'react', 'vue'], }; diff --git a/tests/utils/InstantSearchHooksTestWrapper.tsx b/tests/utils/InstantSearchTestWrapper.tsx similarity index 73% rename from tests/utils/InstantSearchHooksTestWrapper.tsx rename to tests/utils/InstantSearchTestWrapper.tsx index b40c26cd9f..dc2112dc1b 100644 --- a/tests/utils/InstantSearchHooksTestWrapper.tsx +++ b/tests/utils/InstantSearchTestWrapper.tsx @@ -1,19 +1,19 @@ import { createAlgoliaSearchClient } from '@instantsearch/mocks'; import React from 'react'; -import { InstantSearch } from 'react-instantsearch-hooks'; +import { InstantSearch } from 'react-instantsearch-core'; -import type { InstantSearchProps } from 'react-instantsearch-hooks'; +import type { InstantSearchProps } from 'react-instantsearch-core'; const searchClient = createAlgoliaSearchClient({}); -type InstantSearchHooksTestWrapperProps = { +type InstantSearchTestWrapperProps = { children: React.ReactNode; } & Partial; -export function InstantSearchHooksTestWrapper({ +export function InstantSearchTestWrapper({ children, ...props -}: InstantSearchHooksTestWrapperProps) { +}: InstantSearchTestWrapperProps) { return ( {children} diff --git a/tests/utils/createInstantSearchSpy.tsx b/tests/utils/createInstantSearchSpy.tsx index f6ebacb825..5a98f5e44a 100644 --- a/tests/utils/createInstantSearchSpy.tsx +++ b/tests/utils/createInstantSearchSpy.tsx @@ -1,10 +1,10 @@ import React, { createRef } from 'react'; -import { InstantSearch } from '../../packages/react-instantsearch-hooks/src/components/InstantSearch'; -import { IndexContext } from '../../packages/react-instantsearch-hooks/src/lib/IndexContext'; -import { InstantSearchContext } from '../../packages/react-instantsearch-hooks/src/lib/InstantSearchContext'; +import { InstantSearch } from '../../packages/react-instantsearch-core/src/components/InstantSearch'; +import { IndexContext } from '../../packages/react-instantsearch-core/src/lib/IndexContext'; +import { InstantSearchContext } from '../../packages/react-instantsearch-core/src/lib/InstantSearchContext'; -import type { InstantSearchProps } from '../../packages/react-instantsearch-hooks/src'; +import type { InstantSearchProps } from '../../packages/react-instantsearch-core/src'; import type { InstantSearch as InstantSearchType } from 'instantsearch.js'; import type { IndexWidget } from 'instantsearch.js/es/widgets/index/index'; diff --git a/tests/utils/index.ts b/tests/utils/index.ts index 31832ef2c1..7b47088eba 100644 --- a/tests/utils/index.ts +++ b/tests/utils/index.ts @@ -1,7 +1,7 @@ export * from './castToJestMock'; export * from './createInstantSearchSpy'; export * from './enzyme'; -export * from './InstantSearchHooksTestWrapper'; +export * from './InstantSearchTestWrapper'; export * from './normalizeSnapshot'; export * from './runAllMicroTasks'; export * from './wait'; diff --git a/tests/utils/setupTests.ts b/tests/utils/setupTests.ts index 2eb763bbf0..55c4d32916 100644 --- a/tests/utils/setupTests.ts +++ b/tests/utils/setupTests.ts @@ -4,7 +4,7 @@ import { createSerializer } from 'enzyme-to-json'; import htmlSerializer from 'jest-serializer-html/createSerializer'; import '@testing-library/jest-dom/extend-expect'; -import { warnCache } from '../../packages/react-instantsearch-hooks/src/lib/warn'; +import { warnCache } from '../../packages/react-instantsearch-core/src/lib/warn'; import { Vue2, isVue2, diff --git a/tests/versions/index.js b/tests/versions/index.js index f801199d55..b3e3cb16a1 100755 --- a/tests/versions/index.js +++ b/tests/versions/index.js @@ -16,15 +16,7 @@ let hasError = false; react: [ 'react-instantsearch', 'react-instantsearch-core', - 'react-instantsearch-dom', - 'react-instantsearch-dom-maps', - 'react-instantsearch-native', - ], - 'react-hooks': [ - 'react-instantsearch-hooks', - 'react-instantsearch-hooks-web', - 'react-instantsearch-hooks-server', - 'react-instantsearch-hooks-router-nextjs', + 'react-instantsearch-router-nextjs', ], }; @@ -52,7 +44,7 @@ let hasError = false; { const versions = [ { - name: 'react-instantsearch-hooks', + name: 'react-instantsearch-core', versionFile: 'src/version.ts', format: 'esm', }, @@ -61,11 +53,6 @@ let hasError = false; versionFile: 'src/lib/version.ts', format: 'esm', }, - { - name: 'react-instantsearch-core', - versionFile: 'src/core/version.js', - format: 'esm', - }, { name: 'algoliasearch-helper', versionFile: 'src/version.js', diff --git a/tsconfig.json b/tsconfig.json index 7b985a61e7..5f85860b35 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,10 +19,10 @@ "**/es", "**/dist", "tests/e2e", - "examples/react-hooks/next/next-env.d.ts", + "examples/react/next/next-env.d.ts", // @TODO: we need to re-enable type checking in the React Native example // when the RN types work with React 18. - "examples/react-hooks/react-native", + "examples/react/react-native", "packages/create-instantsearch-app/src/templates/**/*" ] } diff --git a/website/_redirects b/website/_redirects index 6a111b7903..70137dc98d 100644 --- a/website/_redirects +++ b/website/_redirects @@ -2,8 +2,8 @@ /examples https://www.algolia.com/doc/guides/building-search-ui/resources/demos/js/ /examples/js/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/ /examples/react/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/react -/examples/hooks/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/react-hooks -/examples/react-hooks/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/react-hooks +/examples/hooks/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/react +/examples/react-hooks/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/react /examples/vue/ https://www.algolia.com/doc/guides/building-search-ui/resources/demos/vue /examples/:flavor/:name/search/* /examples/:flavor/:name/index.html 200 @@ -13,4 +13,5 @@ /examples/media/* /examples/js/media/:splat 301 /examples/tourism/* /examples/js/tourism/:splat 301 +/stories/react/* /stories/js/:splat 301 /stories /stories/js 301! diff --git a/yarn.lock b/yarn.lock index 6d92b9b5ef..35e0e5895d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -170,39 +170,6 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@ant-design/colors@^3.1.0": - version "3.2.2" - resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-3.2.2.tgz#5ad43d619e911f3488ebac303d606e66a8423903" - integrity sha512-YKgNbG2dlzqMhA9NtI3/pbY16m3Yl/EeWBRa+lB1X1YaYxHrxNexiQYCLTWO/uDvAjLFMEDU+zR901waBtMtjQ== - dependencies: - tinycolor2 "^1.4.1" - -"@ant-design/create-react-context@^0.2.4": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@ant-design/create-react-context/-/create-react-context-0.2.5.tgz#f5f5a9163b4772097712837397ad30e22e79f858" - integrity sha512-1rMAa4qgP2lfl/QBH9i78+Gjxtj9FTMpMyDGZsEBW5Kih72EuUo9958mV8PgpRkh4uwPSQ7vVZWXeyNZXVAFDg== - dependencies: - gud "^1.0.0" - warning "^4.0.3" - -"@ant-design/css-animation@^1.7.2": - version "1.7.3" - resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.3.tgz#60a1c970014e86b28f940510d69e503e428f1136" - integrity sha512-LrX0OGZtW+W6iLnTAqnTaoIsRelYeuLZWsrmBJFUXDALQphPsN8cE5DCsmoSlL0QYb94BQxINiuS70Ar/8BNgA== - -"@ant-design/icons-react@~2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@ant-design/icons-react/-/icons-react-2.0.1.tgz#17a2513571ab317aca2927e58cea25dd31e536fb" - integrity sha512-r1QfoltMuruJZqdiKcbPim3d8LNsVPB733U0gZEUSxBLuqilwsW28K2rCTWSMTjmFX7Mfpf+v/wdiFe/XCqThw== - dependencies: - "@ant-design/colors" "^3.1.0" - babel-runtime "^6.26.0" - -"@ant-design/icons@~2.1.1": - version "2.1.1" - resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-2.1.1.tgz#7b9c08dffd4f5d41db667d9dbe5e0107d0bd9a4a" - integrity sha512-jCH+k2Vjlno4YWl6g535nHR09PwCEmTBKAG6VqF+rhkrSPRLfgpU2maagwbZPLjaHuU5Jd1DFQ2KJpQuI6uG8w== - "@astrojs/compiler@^0.29.3": version "0.29.19" resolved "https://registry.yarnpkg.com/@astrojs/compiler/-/compiler-0.29.19.tgz#dd8020a08c18639ce9de5b7203f4a4212d391279" @@ -335,7 +302,7 @@ dependencies: "@babel/highlight" "^7.0.0" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.44", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.14.5", "@babel/code-frame@^7.18.6", "@babel/code-frame@^7.5.5", "@babel/code-frame@^7.8.3": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a" integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q== @@ -402,7 +369,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.12.3", "@babel/core@^7.14.0", "@babel/core@^7.16.0", "@babel/core@^7.18.2", "@babel/core@^7.4.5", "@babel/core@^7.7.2", "@babel/core@^7.7.5", "@babel/core@^7.8.0": +"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.1.6", "@babel/core@^7.12.3", "@babel/core@^7.14.0", "@babel/core@^7.18.2", "@babel/core@^7.7.2", "@babel/core@^7.8.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.20.7.tgz#37072f951bd4d28315445f66e0ec9f6ae0c8c35f" integrity sha512-t1ZjCluspe5DW24bn2Rr1CDb2v9rn/hROtg9a2tmd0+QYf4bsloYfLQzjG4qHPNMhWtKdGC33R5AxGR2Af2cBw== @@ -444,7 +411,7 @@ json5 "^2.2.2" semver "^6.3.1" -"@babel/generator@^7.0.0", "@babel/generator@^7.12.11", "@babel/generator@^7.15.4", "@babel/generator@^7.18.2", "@babel/generator@^7.20.7", "@babel/generator@^7.4.0", "@babel/generator@^7.5.0", "@babel/generator@^7.7.2", "@babel/generator@^7.9.0": +"@babel/generator@^7.15.4", "@babel/generator@^7.18.2", "@babel/generator@^7.20.7", "@babel/generator@^7.4.0", "@babel/generator@^7.5.0", "@babel/generator@^7.7.2", "@babel/generator@^7.9.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.20.7.tgz#f8ef57c8242665c5929fe2e8d82ba75460187b4a" integrity sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw== @@ -507,7 +474,7 @@ lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.5", "@babel/helper-create-class-features-plugin@^7.20.7", "@babel/helper-create-class-features-plugin@^7.4.4": +"@babel/helper-create-class-features-plugin@^7.14.5", "@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.20.5", "@babel/helper-create-class-features-plugin@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.7.tgz#d0e1f8d7e4ed5dac0389364d9c0c191d948ade6f" integrity sha512-LtoWbDXOaidEf50hmdDqn9g8VEzsorMexoWMQdQODbvmqYmaF23pBP5VNPAGIFHsFQCIeKokDiz3CH5Y2jlY6w== @@ -882,13 +849,6 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/plugin-proposal-optional-chaining" "^7.20.7" -"@babel/plugin-external-helpers@^7.0.0": - version "7.2.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-external-helpers/-/plugin-external-helpers-7.2.0.tgz#7f4cb7dee651cd380d2034847d914288467a6be4" - integrity sha512-QFmtcCShFkyAsNtdCM3lJPmRe1iB+vPZymlB4LnDIKEBj2yKQLQKtoxXxJ8ePT5fwMl4QGg303p4mB0UsSI2/g== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-async-generator-functions@^7.15.4", "@babel/plugin-proposal-async-generator-functions@^7.2.0", "@babel/plugin-proposal-async-generator-functions@^7.20.1": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" @@ -907,15 +867,7 @@ "@babel/helper-create-class-features-plugin" "^7.14.5" "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-proposal-class-properties@7.4.4": - version "7.4.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.4.tgz#93a6486eed86d53452ab9bab35e368e9461198ce" - integrity sha512-WjKTI8g8d5w1Bc9zgwSz2nfrsNQsXcCf9J9cdCvrJV6RF56yztwm4TmJC0MgJ9tvwO9gUA/mcYe89bLdGfiXFg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.4.4" - "@babel/helper-plugin-utils" "^7.0.0" - -"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.14.5", "@babel/plugin-proposal-class-properties@^7.16.0", "@babel/plugin-proposal-class-properties@^7.18.6", "@babel/plugin-proposal-class-properties@^7.4.4", "@babel/plugin-proposal-class-properties@^7.7.0": +"@babel/plugin-proposal-class-properties@^7.0.0", "@babel/plugin-proposal-class-properties@^7.1.0", "@babel/plugin-proposal-class-properties@^7.13.0", "@babel/plugin-proposal-class-properties@^7.14.5", "@babel/plugin-proposal-class-properties@^7.18.6", "@babel/plugin-proposal-class-properties@^7.7.0": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== @@ -932,7 +884,7 @@ "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-proposal-decorators@^7.1.0", "@babel/plugin-proposal-decorators@^7.12.9", "@babel/plugin-proposal-decorators@^7.13.15", "@babel/plugin-proposal-decorators@^7.16.4", "@babel/plugin-proposal-decorators@^7.6.0": +"@babel/plugin-proposal-decorators@^7.1.0", "@babel/plugin-proposal-decorators@^7.12.9", "@babel/plugin-proposal-decorators@^7.13.15": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.20.7.tgz#05d37453c2ce818f3e47bbeda9468c8de947eecc" integrity sha512-JB45hbUweYpwAGjkiM7uCyXMENH2lG+9r3G2E+ttc2PRXAoEkpfd/KW5jDg4j8RS6tLtTG1jZi9LbHZVSfs1/A== @@ -983,7 +935,7 @@ "@babel/helper-plugin-utils" "^7.20.2" "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" -"@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.1.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6", "@babel/plugin-proposal-nullish-coalescing-operator@^7.7.4": +"@babel/plugin-proposal-nullish-coalescing-operator@^7.0.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.1.0", "@babel/plugin-proposal-nullish-coalescing-operator@^7.13.8", "@babel/plugin-proposal-nullish-coalescing-operator@^7.14.5", "@babel/plugin-proposal-nullish-coalescing-operator@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz#fdd940a99a740e577d6c753ab6fbb43fdb9467e1" integrity sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA== @@ -991,7 +943,7 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" -"@babel/plugin-proposal-numeric-separator@^7.14.5", "@babel/plugin-proposal-numeric-separator@^7.16.0", "@babel/plugin-proposal-numeric-separator@^7.18.6": +"@babel/plugin-proposal-numeric-separator@^7.14.5", "@babel/plugin-proposal-numeric-separator@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz#899b14fbafe87f053d2c5ff05b36029c62e13c75" integrity sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q== @@ -1018,7 +970,7 @@ "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.1.0", "@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.16.0", "@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7", "@babel/plugin-proposal-optional-chaining@^7.7.5": +"@babel/plugin-proposal-optional-chaining@^7.0.0", "@babel/plugin-proposal-optional-chaining@^7.1.0", "@babel/plugin-proposal-optional-chaining@^7.13.12", "@babel/plugin-proposal-optional-chaining@^7.14.5", "@babel/plugin-proposal-optional-chaining@^7.18.9", "@babel/plugin-proposal-optional-chaining@^7.20.7": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz#49f2b372519ab31728cc14115bb0998b15bfda55" integrity sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ== @@ -1027,7 +979,7 @@ "@babel/helper-skip-transparent-expression-wrappers" "^7.20.0" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-proposal-private-methods@^7.13.0", "@babel/plugin-proposal-private-methods@^7.14.5", "@babel/plugin-proposal-private-methods@^7.16.0", "@babel/plugin-proposal-private-methods@^7.18.6": +"@babel/plugin-proposal-private-methods@^7.13.0", "@babel/plugin-proposal-private-methods@^7.14.5", "@babel/plugin-proposal-private-methods@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== @@ -1235,7 +1187,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-async-to-generator@^7.0.0", "@babel/plugin-transform-async-to-generator@^7.14.5", "@babel/plugin-transform-async-to-generator@^7.18.6", "@babel/plugin-transform-async-to-generator@^7.3.4", "@babel/plugin-transform-async-to-generator@^7.4.4": +"@babel/plugin-transform-async-to-generator@^7.14.5", "@babel/plugin-transform-async-to-generator@^7.18.6", "@babel/plugin-transform-async-to-generator@^7.3.4", "@babel/plugin-transform-async-to-generator@^7.4.4": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz#dfee18623c8cb31deb796aa3ca84dda9cea94354" integrity sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q== @@ -1311,7 +1263,7 @@ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.14.5", "@babel/plugin-transform-flow-strip-types@^7.16.0": +"@babel/plugin-transform-flow-strip-types@^7.0.0", "@babel/plugin-transform-flow-strip-types@^7.14.5": version "7.19.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.19.0.tgz#e9e8606633287488216028719638cbbb2f2dde8f" integrity sha512-sgeMlNaQVbCSpgLSKP4ZZKfsJVnFnNQlUSk6gPYzR/q7tzCgQF2t8RBKAP6cKJeZdveei7Q7Jm527xepI8lNLg== @@ -1365,7 +1317,7 @@ "@babel/helper-module-transforms" "^7.20.7" "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.1.0", "@babel/plugin-transform-modules-commonjs@^7.15.4", "@babel/plugin-transform-modules-commonjs@^7.19.6", "@babel/plugin-transform-modules-commonjs@^7.2.0", "@babel/plugin-transform-modules-commonjs@^7.4.4", "@babel/plugin-transform-modules-commonjs@^7.5.0": +"@babel/plugin-transform-modules-commonjs@^7.0.0", "@babel/plugin-transform-modules-commonjs@^7.1.0", "@babel/plugin-transform-modules-commonjs@^7.15.4", "@babel/plugin-transform-modules-commonjs@^7.19.6", "@babel/plugin-transform-modules-commonjs@^7.2.0", "@babel/plugin-transform-modules-commonjs@^7.4.4": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.7.tgz#abb5f84695e74d46acf48244082f6cbf8bb23120" integrity sha512-76jqqFiFdCD+RJwEdtBHUG2/rEKQAmpejPbAKyQECEE3/y4U5CMPc9IXvipS990vgQhzq+ZRw6WJ+q4xJ/P24w== @@ -1452,21 +1404,21 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" -"@babel/plugin-transform-react-constant-elements@^7.0.0", "@babel/plugin-transform-react-constant-elements@^7.2.0", "@babel/plugin-transform-react-constant-elements@^7.6.3": +"@babel/plugin-transform-react-constant-elements@^7.2.0": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-constant-elements/-/plugin-transform-react-constant-elements-7.20.2.tgz#3f02c784e0b711970d7d8ccc96c4359d64e27ac7" integrity sha512-KS/G8YI8uwMGKErLFOHS/ekhqdHhpEloxs43NecQHVgo2QuQSyJhGIY1fL8UGl9wy5ItVwwoUL4YxVqsplGq2g== dependencies: "@babel/helper-plugin-utils" "^7.20.2" -"@babel/plugin-transform-react-display-name@^7.0.0", "@babel/plugin-transform-react-display-name@^7.14.5", "@babel/plugin-transform-react-display-name@^7.16.0", "@babel/plugin-transform-react-display-name@^7.18.6": +"@babel/plugin-transform-react-display-name@^7.0.0", "@babel/plugin-transform-react-display-name@^7.14.5": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.18.6.tgz#8b1125f919ef36ebdfff061d664e266c666b9415" integrity sha512-TV4sQ+T013n61uMoygyMRm+xf04Bd5oqFpv2jAEQwSZ8NwQA7zeRPg1LMVg2PWi3zWBz+CLKD+v5bcpZ/BS0aA== dependencies: "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-transform-react-jsx-development@^7.14.5", "@babel/plugin-transform-react-jsx-development@^7.18.6": +"@babel/plugin-transform-react-jsx-development@^7.14.5": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.18.6.tgz#dbe5c972811e49c7405b630e4d0d2e1380c0ddc5" integrity sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA== @@ -1498,7 +1450,7 @@ "@babel/plugin-syntax-jsx" "^7.18.6" "@babel/types" "^7.20.7" -"@babel/plugin-transform-react-pure-annotations@^7.14.5", "@babel/plugin-transform-react-pure-annotations@^7.18.6": +"@babel/plugin-transform-react-pure-annotations@^7.14.5": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.18.6.tgz#561af267f19f3e5d59291f9950fd7b9663d0d844" integrity sha512-I8VfEPg9r2TRDdvnHgPepTKvuRomzA8+u+nhY7qSI1fR2hRNebasZEETLyM5mAUr0Ku56OkXJ0I7NHJnO6cJiQ== @@ -1533,7 +1485,7 @@ babel-plugin-polyfill-regenerator "^0.2.2" semver "^6.3.0" -"@babel/plugin-transform-runtime@^7.0.0", "@babel/plugin-transform-runtime@^7.13.15", "@babel/plugin-transform-runtime@^7.16.4", "@babel/plugin-transform-runtime@^7.4.0": +"@babel/plugin-transform-runtime@^7.0.0", "@babel/plugin-transform-runtime@^7.13.15", "@babel/plugin-transform-runtime@^7.4.0": version "7.19.6" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz#9d2a9dbf4e12644d6f46e5e75bfbf02b5d6e9194" integrity sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw== @@ -1581,7 +1533,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.18.9" -"@babel/plugin-transform-typescript@^7.0.0", "@babel/plugin-transform-typescript@^7.15.0", "@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.5.0": +"@babel/plugin-transform-typescript@^7.15.0", "@babel/plugin-transform-typescript@^7.18.6", "@babel/plugin-transform-typescript@^7.5.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.20.7.tgz#673f49499cd810ae32a1ea5f3f8fab370987e055" integrity sha512-m3wVKEvf6SoszD8pu4NZz3PvfKRCMgk6D6d0Qi9hNnlM5M6CFS92EgF4EiHVLKbU0r/r7ty1hg7NPZwE7WRbYw== @@ -1805,7 +1757,7 @@ js-levenshtein "^1.1.3" semver "^5.3.0" -"@babel/preset-env@^7.1.6", "@babel/preset-env@^7.12.9", "@babel/preset-env@^7.14.1", "@babel/preset-env@^7.16.4", "@babel/preset-env@^7.4.4", "@babel/preset-env@^7.4.5", "@babel/preset-env@^7.6.3": +"@babel/preset-env@^7.1.6", "@babel/preset-env@^7.12.9", "@babel/preset-env@^7.14.1", "@babel/preset-env@^7.4.5": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.20.2.tgz#9b1642aa47bb9f43a86f9630011780dab7f86506" integrity sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg== @@ -1938,18 +1890,6 @@ "@babel/plugin-transform-react-jsx-development" "^7.14.5" "@babel/plugin-transform-react-pure-annotations" "^7.14.5" -"@babel/preset-react@^7.0.0", "@babel/preset-react@^7.16.0": - version "7.18.6" - resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.18.6.tgz#979f76d6277048dc19094c217b507f3ad517dd2d" - integrity sha512-zXr6atUmyYdiWRVLOZahakYmOBHtWc2WGCkP8PYTgZi0iJXDY2CN180TdrIW4OGOAdLc7TifzDIvtx6izaRIzg== - dependencies: - "@babel/helper-plugin-utils" "^7.18.6" - "@babel/helper-validator-option" "^7.18.6" - "@babel/plugin-transform-react-display-name" "^7.18.6" - "@babel/plugin-transform-react-jsx" "^7.18.6" - "@babel/plugin-transform-react-jsx-development" "^7.18.6" - "@babel/plugin-transform-react-pure-annotations" "^7.18.6" - "@babel/preset-typescript@7.15.0": version "7.15.0" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.15.0.tgz#e8fca638a1a0f64f14e1119f7fe4500277840945" @@ -1959,7 +1899,7 @@ "@babel/helper-validator-option" "^7.14.5" "@babel/plugin-transform-typescript" "^7.15.0" -"@babel/preset-typescript@^7.1.0", "@babel/preset-typescript@^7.16.0", "@babel/preset-typescript@^7.3.3": +"@babel/preset-typescript@^7.1.0": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.18.6.tgz#ce64be3e63eddc44240c6358daefac17b3186399" integrity sha512-s9ik86kXBAnD760aybBucdpnLsAt0jK1xqJn2juOn9lkOvSHV60os5hxoVJsPzMQxvnUJFAlkont2DvvaYEBtQ== @@ -1979,7 +1919,7 @@ "@babel/plugin-transform-modules-commonjs" "^7.22.5" "@babel/plugin-transform-typescript" "^7.22.5" -"@babel/register@^7.0.0", "@babel/register@^7.8.3": +"@babel/register@^7.0.0": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.16.7.tgz#e7b3a6015d1646677538672106bdb3a0b4a07657" integrity sha512-Ft+cuxorVxFj4RrPDs9TbJNE7ZbuJTyazUC6jLWRvBQT/qIDZPMe7MHgjlrA+11+XDLh+I0Pnx7sxPp4LRhzcA== @@ -2031,7 +1971,7 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.0.0-beta.46", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.0", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6": +"@babel/runtime@^7.0.0", "@babel/runtime@^7.0.0-beta.46", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.14.0", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.3", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2", "@babel/runtime@^7.9.6": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.7.tgz#fcb41a5a70550e04a7b708037c7c32f7f356d8fd" integrity sha512-UF0tvkUtxwAgZ5W/KrkHf0Rn0fdnLDU9ScxBrEVNUprE/MzirjK4MJUX1/BVDv00Sv8cljtukVK1aky++X1SjQ== @@ -2056,7 +1996,7 @@ "@babel/parser" "^7.22.5" "@babel/types" "^7.22.5" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.6", "@babel/traverse@^7.11.5", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.18.2", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2", "@babel/traverse@^7.9.0": +"@babel/traverse@^7.0.0", "@babel/traverse@^7.11.5", "@babel/traverse@^7.13.0", "@babel/traverse@^7.15.4", "@babel/traverse@^7.18.2", "@babel/traverse@^7.20.5", "@babel/traverse@^7.20.7", "@babel/traverse@^7.4.3", "@babel/traverse@^7.7.0", "@babel/traverse@^7.7.2", "@babel/traverse@^7.9.0": version "7.20.8" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.8.tgz#e3a23eb04af24f8bbe8a8ba3eef6155b77df0b08" integrity sha512-/RNkaYDeCy4MjyV70+QkSHhxbvj2JO/5Ft2Pa880qJOG8tWrqcT/wXUuCCv43yogfqPzHL77Xu101KQPf4clnQ== @@ -2088,7 +2028,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.18.4", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.2.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.9.0": +"@babel/types@^7.0.0", "@babel/types@^7.15.4", "@babel/types@^7.15.6", "@babel/types@^7.18.4", "@babel/types@^7.18.6", "@babel/types@^7.18.9", "@babel/types@^7.19.0", "@babel/types@^7.20.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.20.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.0", "@babel/types@^7.4.4", "@babel/types@^7.7.0", "@babel/types@^7.9.0": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.7.tgz#54ec75e252318423fc07fb644dc6a58a64c09b7f" integrity sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg== @@ -2246,13 +2186,6 @@ resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36" integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== -"@egjs/hammerjs@^2.0.17": - version "2.0.17" - resolved "https://registry.yarnpkg.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz#5dc02af75a6a06e4c2db0202cae38c9263895124" - integrity sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A== - dependencies: - "@types/hammerjs" "^2.0.36" - "@emmetio/abbreviation@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@emmetio/abbreviation/-/abbreviation-2.2.3.tgz#2b3c0383c1a4652f677d5b56fb3f1616fe16ef10" @@ -2404,20 +2337,6 @@ resolved "https://registry.yarnpkg.com/@expo/apple-utils/-/apple-utils-0.0.0-alpha.26.tgz#cf5a893b7c9cc779af5b54a482196325dcde1426" integrity sha512-t+xOhn4bYSAXkXamhDPUiI2Ol+QIwHRHLn/2QiCmNAGHolaVan/hMaVveSzvCYitpaJ16b4nthvcWFoJipxGlA== -"@expo/babel-preset-cli@0.2.7": - version "0.2.7" - resolved "https://registry.yarnpkg.com/@expo/babel-preset-cli/-/babel-preset-cli-0.2.7.tgz#251b60e530943d2b29a1065295001039410e9a69" - integrity sha512-NWL5S4ODDi+dRsQRSu0x8w/m4rr55ZH+5qpb2ixB8Nojlq4dEt7EV2bHB6IPxT1XbJau4/IZiG6oN6XdRDHm+w== - dependencies: - "@babel/core" "^7.4.5" - "@babel/plugin-proposal-class-properties" "^7.4.4" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.7.4" - "@babel/plugin-proposal-optional-chaining" "^7.7.5" - "@babel/plugin-transform-modules-commonjs" "^7.5.0" - "@babel/preset-env" "^7.4.4" - "@babel/preset-typescript" "^7.3.3" - typescript "3.7.3" - "@expo/bunyan@4.0.0", "@expo/bunyan@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@expo/bunyan/-/bunyan-4.0.0.tgz#be0c1de943c7987a9fbd309ea0b1acd605890c7b" @@ -2537,23 +2456,6 @@ slugify "^1.3.4" sucrase "^3.20.0" -"@expo/config@^2.5.3": - version "2.7.0" - resolved "https://registry.yarnpkg.com/@expo/config/-/config-2.7.0.tgz#8f03b99b72ff2ee113d2b82e7e485206e3b95cb4" - integrity sha512-19FT0RLA7vRDTBF2ftwEJsmIcYrwP/PxsBZNs2W5NpgBX20DYZLp82ptjeHonP12rzYmynDhMiGdD4tXtZyBzw== - dependencies: - "@babel/register" "^7.8.3" - "@expo/babel-preset-cli" "0.2.7" - "@expo/json-file" "8.2.7" - "@types/invariant" "^2.2.30" - find-yarn-workspace-root "^1.2.1" - fs-extra "^7.0.1" - invariant "^2.2.4" - jest-message-util "^25.1.0" - resolve-from "^5.0.0" - slugify "^1.3.4" - xml2js "^0.4.23" - "@expo/config@^6.0.6": version "6.0.18" resolved "https://registry.yarnpkg.com/@expo/config/-/config-6.0.18.tgz#fb3dd2dcf319a7ced77765c43e6825de4e14dff8" @@ -2661,18 +2563,6 @@ json5 "^1.0.1" write-file-atomic "^2.3.0" -"@expo/json-file@8.2.7": - version "8.2.7" - resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-8.2.7.tgz#61611b0fd62c99cb4bf1e73052ea9da08c488e40" - integrity sha512-VhaVj6EI95uwK4SDKEFGmp4Zt70RB67s7+zgGK5t92e8twFz3WAvz7J5Qn/78vGL3xWrV7Mn6ZOILDCuMeXW/A== - dependencies: - "@babel/code-frame" "^7.0.0-beta.44" - fs-extra "^8.0.1" - json5 "^1.0.1" - lodash "^4.17.15" - util.promisify "^1.0.0" - write-file-atomic "^2.3.0" - "@expo/metro-config@0.3.10": version "0.3.10" resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.3.10.tgz#99e37f12b98ec425b7d739fc2aeb9cf6a61249aa" @@ -2799,13 +2689,6 @@ dependencies: cross-spawn "^7.0.3" -"@expo/vector-icons@^10.0.2": - version "10.2.1" - resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-10.2.1.tgz#47fb2fa12d7ad601835babde6bd3ddea7f6fde89" - integrity sha512-clYQZFLeU2y23n03hXg18EEsZS5c73sJJnfderztfSAqkUXkfUtv07fwuprYwbHIvgFkw6L7R6xJOCVYtS85iQ== - dependencies: - lodash "^4.17.4" - "@expo/vector-icons@^12.0.4": version "12.0.5" resolved "https://registry.yarnpkg.com/@expo/vector-icons/-/vector-icons-12.0.5.tgz#bc508ad05fb7e9a3e008704977cfec6c18aa7728" @@ -2853,17 +2736,6 @@ webpack "4.43.0" webpack-manifest-plugin "~2.2.0" -"@expo/websql@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@expo/websql/-/websql-1.0.1.tgz#fff0cf9c1baa1f70f9e1d658b7c39a420d9b10a9" - integrity sha1-//DPnBuqH3D54dZYt8OaQg2bEKk= - dependencies: - argsarray "^0.0.1" - immediate "^3.2.2" - noop-fn "^1.0.0" - pouchdb-collections "^1.0.1" - tiny-queue "^0.2.1" - "@expo/xcpretty@^4.1.0": version "4.1.0" resolved "https://registry.yarnpkg.com/@expo/xcpretty/-/xcpretty-4.1.0.tgz#63a1b54635f1e67250bfe74d58f25d2b52c5818a" @@ -2904,7 +2776,7 @@ resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.2.1.tgz#9551142a1980503752536b5050fd99f4a7f13b17" integrity sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw== -"@hapi/joi@^15.0.1", "@hapi/joi@^15.0.3": +"@hapi/joi@^15.0.1": version "15.1.1" resolved "https://registry.yarnpkg.com/@hapi/joi/-/joi-15.1.1.tgz#c675b8a71296f02833f8d6d243b34c57b8ce19d7" integrity sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ== @@ -3023,12 +2895,12 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": +"@istanbuljs/schema@^0.1.2": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^24.7.1", "@jest/console@^24.9.0": +"@jest/console@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== @@ -3049,40 +2921,6 @@ jest-util "^27.4.2" slash "^3.0.0" -"@jest/core@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" - integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== - dependencies: - "@jest/console" "^24.7.1" - "@jest/reporters" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-changed-files "^24.9.0" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-resolve-dependencies "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - jest-watcher "^24.9.0" - micromatch "^3.1.10" - p-each-series "^1.0.0" - realpath-native "^1.1.0" - rimraf "^2.5.4" - slash "^2.0.0" - strip-ansi "^5.0.0" - "@jest/core@^27.4.7": version "27.4.7" resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.4.7.tgz#84eabdf42a25f1fa138272ed229bcf0a1b5e6913" @@ -3124,16 +2962,6 @@ dependencies: "@jest/types" "^26.6.2" -"@jest/environment@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" - integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== - dependencies: - "@jest/fake-timers" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - "@jest/environment@^27.1.0", "@jest/environment@^27.4.6": version "27.4.6" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.4.6.tgz#1e92885d64f48c8454df35ed9779fbcf31c56d8b" @@ -3174,33 +3002,6 @@ "@jest/types" "^27.4.2" expect "^27.4.6" -"@jest/reporters@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" - integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.2" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.2.6" - jest-haste-map "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - node-notifier "^5.4.2" - slash "^2.0.0" - source-map "^0.6.0" - string-length "^2.0.0" - "@jest/reporters@^27.4.6": version "27.4.6" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.4.6.tgz#b53dec3a93baf9b00826abf95b932de919d6d8dd" @@ -3232,7 +3033,7 @@ terminal-link "^2.0.0" v8-to-istanbul "^8.1.0" -"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": +"@jest/source-map@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== @@ -3269,16 +3070,6 @@ "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" - integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== - dependencies: - "@jest/test-result" "^24.9.0" - jest-haste-map "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - "@jest/test-sequencer@^27.4.6": version "27.4.6" resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz#447339b8a3d7b5436f50934df30854e442a9d904" @@ -3341,16 +3132,6 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" -"@jest/types@^25.5.0": - version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" - integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^15.0.0" - chalk "^3.0.0" - "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" @@ -3426,14 +3207,6 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.9": - version "0.3.17" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" - integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== - dependencies: - "@jridgewell/resolve-uri" "3.1.0" - "@jridgewell/sourcemap-codec" "1.4.14" - "@jridgewell/trace-mapping@^0.3.17": version "0.3.18" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" @@ -3442,6 +3215,14 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.9": + version "0.3.17" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985" + integrity sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@jsdoc/salty@^0.2.1": version "0.2.5" resolved "https://registry.yarnpkg.com/@jsdoc/salty/-/salty-0.2.5.tgz#1b2fa5bb8c66485b536d86eee877c263d322f692" @@ -4355,11 +4136,6 @@ resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.6.tgz#5f44823a78335355f00f1687cfc4f1dafa3eca08" integrity sha512-Te/OBDXFSodPU6jlXYPAXpmZr/AkG6DCATAxttQxqOWaq6eDFX25Db3dK0120GZrSZmv4QCe9KsZmJKDbWs4OA== -"@next/env@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/env/-/env-12.3.1.tgz#18266bd92de3b4aa4037b1927aa59e6f11879260" - integrity sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg== - "@next/eslint-plugin-next@12.0.7": version "12.0.7" resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.0.7.tgz#2c71bb66b8f8ff1080086342113406aa3156976f" @@ -4372,126 +4148,61 @@ resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.1.6.tgz#79a35349b98f2f8c038ab6261aa9cd0d121c03f9" integrity sha512-BxBr3QAAAXWgk/K7EedvzxJr2dE014mghBSA9iOEAv0bMgF+MRq4PoASjuHi15M2zfowpcRG8XQhMFtxftCleQ== -"@next/swc-android-arm-eabi@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz#b15ce8ad376102a3b8c0f3c017dde050a22bb1a3" - integrity sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ== - "@next/swc-android-arm64@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.6.tgz#ec08ea61794f8752c8ebcacbed0aafc5b9407456" integrity sha512-EboEk3ROYY7U6WA2RrMt/cXXMokUTXXfnxe2+CU+DOahvbrO8QSWhlBl9I9ZbFzJx28AGB9Yo3oQHCvph/4Lew== -"@next/swc-android-arm64@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz#85d205f568a790a137cb3c3f720d961a2436ac9c" - integrity sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q== - "@next/swc-darwin-arm64@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.6.tgz#d1053805615fd0706e9b1667893a72271cd87119" integrity sha512-P0EXU12BMSdNj1F7vdkP/VrYDuCNwBExtRPDYawgSUakzi6qP0iKJpya2BuLvNzXx+XPU49GFuDC5X+SvY0mOw== -"@next/swc-darwin-arm64@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz#b105457d6760a7916b27e46c97cb1a40547114ae" - integrity sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg== - "@next/swc-darwin-x64@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.6.tgz#2d1b926a22f4c5230d5b311f9c56cfdcc406afec" integrity sha512-9FptMnbgHJK3dRDzfTpexs9S2hGpzOQxSQbe8omz6Pcl7rnEp9x4uSEKY51ho85JCjL4d0tDLBcXEJZKKLzxNg== -"@next/swc-darwin-x64@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz#6947b39082271378896b095b6696a7791c6e32b1" - integrity sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA== - -"@next/swc-freebsd-x64@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz#2b6c36a4d84aae8b0ea0e0da9bafc696ae27085a" - integrity sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q== - "@next/swc-linux-arm-gnueabihf@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.6.tgz#c021918d2a94a17f823106a5e069335b8a19724f" integrity sha512-PvfEa1RR55dsik/IDkCKSFkk6ODNGJqPY3ysVUZqmnWMDSuqFtf7BPWHFa/53znpvVB5XaJ5Z1/6aR5CTIqxPw== -"@next/swc-linux-arm-gnueabihf@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz#6e421c44285cfedac1f4631d5de330dd60b86298" - integrity sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w== - "@next/swc-linux-arm64-gnu@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.6.tgz#ac55c07bfabde378dfa0ce2b8fc1c3b2897e81ae" integrity sha512-53QOvX1jBbC2ctnmWHyRhMajGq7QZfl974WYlwclXarVV418X7ed7o/EzGY+YVAEKzIVaAB9JFFWGXn8WWo0gQ== -"@next/swc-linux-arm64-gnu@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz#8863f08a81f422f910af126159d2cbb9552ef717" - integrity sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ== - "@next/swc-linux-arm64-musl@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.6.tgz#e429f826279894be9096be6bec13e75e3d6bd671" integrity sha512-CMWAkYqfGdQCS+uuMA1A2UhOfcUYeoqnTW7msLr2RyYAys15pD960hlDfq7QAi8BCAKk0sQ2rjsl0iqMyziohQ== -"@next/swc-linux-arm64-musl@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz#0038f07cf0b259d70ae0c80890d826dfc775d9f3" - integrity sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg== - "@next/swc-linux-x64-gnu@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.6.tgz#1f276c0784a5ca599bfa34b2fcc0b38f3a738e08" integrity sha512-AC7jE4Fxpn0s3ujngClIDTiEM/CQiB2N2vkcyWWn6734AmGT03Duq6RYtPMymFobDdAtZGFZd5nR95WjPzbZAQ== -"@next/swc-linux-x64-gnu@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz#c66468f5e8181ffb096c537f0dbfb589baa6a9c1" - integrity sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA== - "@next/swc-linux-x64-musl@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.6.tgz#1d9933dd6ba303dcfd8a2acd6ac7c27ed41e2eea" integrity sha512-c9Vjmi0EVk0Kou2qbrynskVarnFwfYIi+wKufR9Ad7/IKKuP6aEhOdZiIIdKsYWRtK2IWRF3h3YmdnEa2WLUag== -"@next/swc-linux-x64-musl@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz#c6269f3e96ac0395bc722ad97ce410ea5101d305" - integrity sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg== - "@next/swc-win32-arm64-msvc@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.6.tgz#2ef9837f12ca652b1783d72ecb86208906042f02" integrity sha512-3UTOL/5XZSKFelM7qN0it35o3Cegm6LsyuERR3/OoqEExyj3aCk7F025b54/707HTMAnjlvQK3DzLhPu/xxO4g== -"@next/swc-win32-arm64-msvc@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz#83c639ee969cee36ce247c3abd1d9df97b5ecade" - integrity sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw== - "@next/swc-win32-ia32-msvc@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.6.tgz#74003d0aa1c59dfa56cb15481a5c607cbc0027b9" integrity sha512-8ZWoj6nCq6fI1yCzKq6oK0jE6Mxlz4MrEsRyu0TwDztWQWe7rh4XXGLAa2YVPatYcHhMcUL+fQQbqd1MsgaSDA== -"@next/swc-win32-ia32-msvc@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz#52995748b92aa8ad053440301bc2c0d9fbcf27c2" - integrity sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA== - "@next/swc-win32-x64-msvc@12.1.6": version "12.1.6" resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.6.tgz#a350caf42975e7197b24b495b8d764eec7e6a36e" integrity sha512-4ZEwiRuZEicXhXqmhw3+de8Z4EpOLQj/gp+D9fFWo6ii6W1kBkNNvvEx4A90ugppu+74pT1lIJnOuz3A9oQeJA== -"@next/swc-win32-x64-msvc@12.3.1": - version "12.3.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz#27d71a95247a9eaee03d47adee7e3bd594514136" - integrity sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA== - "@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents.2": version "2.1.8-no-fsevents.2" resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.2.tgz#e324c0a247a5567192dd7180647709d7e2faf94b" @@ -6477,11 +6188,6 @@ dependencies: tsm "^2.1.4" -"@ptomasroos/react-native-multi-slider@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@ptomasroos/react-native-multi-slider/-/react-native-multi-slider-2.2.2.tgz#35a97fb8c355627c6a2ded010b360ac5728b44ad" - integrity sha512-HWyCnRD3Z3SbHK2FLWYmBBqd1B4iXipeKv1+AK0FoY/CElEDTEixHE8hN60TsqxalPrznn798LE2Q4tHuCiyaA== - "@reach/router@^1.2.1": version "1.3.4" resolved "https://registry.yarnpkg.com/@reach/router/-/router-1.3.4.tgz#d2574b19370a70c80480ed91f3da840136d10f8c" @@ -6492,13 +6198,6 @@ prop-types "^15.6.1" react-lifecycles-compat "^3.0.4" -"@react-native-community/cli-debugger-ui@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-3.0.0.tgz#d01d08d1e5ddc1633d82c7d84d48fff07bd39416" - integrity sha512-m3X+iWLsK/H7/b7PpbNO33eQayR/+M26la4ZbYe1KRke5Umg4PIWsvg21O8Tw4uJcY8LA5hsP+rBi/syBkBf0g== - dependencies: - serve-static "^1.13.1" - "@react-native-community/cli-debugger-ui@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-5.0.1.tgz#6b1f3367b8e5211e899983065ea2e72c1901d75f" @@ -6517,19 +6216,6 @@ hermes-profile-transformer "^0.0.6" ip "^1.1.5" -"@react-native-community/cli-platform-android@^3.0.0-alpha.1": - version "3.1.4" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-3.1.4.tgz#61f964dc311623e60b0fb29c5f3732cc8a6f076f" - integrity sha512-ClSdY20F0gzWVLTqCv7vHjnUqOcuq10jd9GgHX6lGSc2GI+Ql3/aQg3tmG4uY3KXNNwAv3U8QCoYgg1WGfwiHA== - dependencies: - "@react-native-community/cli-tools" "^3.0.0" - chalk "^2.4.2" - execa "^1.0.0" - jetifier "^1.6.2" - logkitty "^0.6.0" - slash "^3.0.0" - xmldoc "^1.1.2" - "@react-native-community/cli-platform-android@^5.0.1", "@react-native-community/cli-platform-android@^5.0.1-alpha.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-android/-/cli-platform-android-5.0.1.tgz#7f761e1818e5a099877ec59a1b739553fd6a6905" @@ -6546,16 +6232,6 @@ slash "^3.0.0" xmldoc "^1.1.2" -"@react-native-community/cli-platform-ios@^3.0.0-alpha.1": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-3.2.0.tgz#c469444f5993c9e6737a4b16d78cf033e3702f00" - integrity sha512-pzEnx68H6+mHBq5jsMrr3UmAmkrLSMlC9BZ4yoUdfUXCQq6/R70zNYvH4hjUw8h2Al7Kgq53UzHUsM0ph8TSWQ== - dependencies: - "@react-native-community/cli-tools" "^3.0.0" - chalk "^2.4.2" - js-yaml "^3.13.1" - xcode "^2.0.0" - "@react-native-community/cli-platform-ios@^5.0.1-alpha.1": version "5.0.2" resolved "https://registry.yarnpkg.com/@react-native-community/cli-platform-ios/-/cli-platform-ios-5.0.2.tgz#62485534053c0dad28a67de188248de177f4b0fb" @@ -6584,16 +6260,6 @@ serve-static "^1.13.1" ws "^1.1.0" -"@react-native-community/cli-tools@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-3.0.0.tgz#fe48b80822ed7e49b8af051f9fe41e22a2a710b1" - integrity sha512-8IhQKZdf3E4CR8T7HhkPGgorot/cLkRDgneJFDSWk/wCYZAuUh4NEAdumQV7N0jLSMWX7xxiWUPi94lOBxVY9g== - dependencies: - chalk "^2.4.2" - lodash "^4.17.5" - mime "^2.4.1" - node-fetch "^2.5.0" - "@react-native-community/cli-tools@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-tools/-/cli-tools-5.0.1.tgz#9ee564dbe20448becd6bce9fbea1b59aa5797919" @@ -6606,11 +6272,6 @@ open "^6.2.0" shell-quote "1.6.1" -"@react-native-community/cli-types@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-3.0.0.tgz#488d46605cb05e88537e030f38da236eeda74652" - integrity sha512-ng6Tm537E/M42GjE4TRUxQyL8sRfClcL7bQWblOCoxPZzJ2J3bdALsjeG3vDnVCIfI/R0AeFalN9KjMt0+Z/Zg== - "@react-native-community/cli-types@^5.0.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli-types/-/cli-types-5.0.1.tgz#8c5db4011988b0836d27a5efe230cb34890915dc" @@ -6618,52 +6279,6 @@ dependencies: ora "^3.4.0" -"@react-native-community/cli@^3.0.0-alpha.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-3.2.1.tgz#2a466801eb6080a1f73358c5d740c53c24ed8c6f" - integrity sha512-bZ/bfZ+9r1gQSxp6t7+00DcpC6vmbVYSvzUCFM/yo5k8bhsDdcy8aocscIaXXVGG+v9Edri/Q7hH9ks7L18/Rg== - dependencies: - "@hapi/joi" "^15.0.3" - "@react-native-community/cli-debugger-ui" "^3.0.0" - "@react-native-community/cli-tools" "^3.0.0" - "@react-native-community/cli-types" "^3.0.0" - chalk "^2.4.2" - command-exists "^1.2.8" - commander "^2.19.0" - compression "^1.7.1" - connect "^3.6.5" - cosmiconfig "^5.1.0" - deepmerge "^3.2.0" - didyoumean "^1.2.1" - envinfo "^7.1.0" - errorhandler "^1.5.0" - execa "^1.0.0" - find-up "^4.1.0" - fs-extra "^7.0.1" - glob "^7.1.1" - graceful-fs "^4.1.3" - inquirer "^3.0.6" - lodash "^4.17.5" - metro "^0.56.0" - metro-config "^0.56.0" - metro-core "^0.56.0" - metro-react-native-babel-transformer "^0.56.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - morgan "^1.9.0" - node-notifier "^5.2.1" - open "^6.2.0" - ora "^3.4.0" - plist "^3.0.0" - pretty-format "^25.1.0" - semver "^6.3.0" - serve-static "^1.13.1" - shell-quote "1.6.1" - strip-ansi "^5.2.0" - sudo-prompt "^9.0.0" - wcwidth "^1.0.1" - ws "^1.1.0" - "@react-native-community/cli@^5.0.1-alpha.1": version "5.0.1" resolved "https://registry.yarnpkg.com/@react-native-community/cli/-/cli-5.0.1.tgz#1f7a66d813d5daf102e593f3c550650fa0cc8314" @@ -6727,24 +6342,6 @@ resolved "https://registry.yarnpkg.com/@react-native/polyfills/-/polyfills-1.0.0.tgz#05bb0031533598f9458cf65a502b8df0eecae780" integrity sha512-0jbp4RxjYopTsIdLl+/Fy2TiwVYHy4mgeu07DG4b/LyM0OS/+lPP5c9sbnt/AMlnF6qz2JRZpPpGw1eMNS6A4w== -"@react-navigation/core@^3.7.9": - version "3.7.9" - resolved "https://registry.yarnpkg.com/@react-navigation/core/-/core-3.7.9.tgz#3f7ba0fcb6c8d74a77a057382af198d84c7c4e3b" - integrity sha512-EknbzM8OI9A5alRxXtQRV5Awle68B+z1QAxNty5DxmlS3BNfmduWNGnim159ROyqxkuDffK9L/U/Tbd45mx+Jg== - dependencies: - hoist-non-react-statics "^3.3.2" - path-to-regexp "^1.8.0" - query-string "^6.13.6" - react-is "^16.13.0" - -"@react-navigation/native@^3.8.4": - version "3.8.4" - resolved "https://registry.yarnpkg.com/@react-navigation/native/-/native-3.8.4.tgz#4d77f86506364ecf18b33c7f8740afb6763d0b37" - integrity sha512-gXSVcL7bfFDyVkvyg1FiAqTCIgZub5K1X/TZqURBs2CPqDpfX1OsCtB9D33eTF14SpbfgHW866btqrrxoCACfg== - dependencies: - hoist-non-react-statics "^3.3.2" - react-native-safe-area-view "^0.14.9" - "@rushstack/eslint-patch@^1.0.8": version "1.1.0" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.0.tgz#7f698254aadf921e48dda8c0a6b304026b8a9323" @@ -7197,33 +6794,6 @@ pretty-hrtime "^1.0.3" regenerator-runtime "^0.13.3" -"@storybook/react@5.3.9": - version "5.3.9" - resolved "https://registry.yarnpkg.com/@storybook/react/-/react-5.3.9.tgz#cf3a954b5d0430c5a3558ea5df305bb70e2af3cd" - integrity sha512-pOc6xw1c83fUnTRcCpIrtLLDKkZUhW3EkNvwYyMHrGXMRcgDETAlpoxBMHXpnbfV7qaAsE/UAVQQ1rRq5pgPBA== - dependencies: - "@babel/plugin-transform-react-constant-elements" "^7.6.3" - "@babel/preset-flow" "^7.0.0" - "@babel/preset-react" "^7.0.0" - "@storybook/addons" "5.3.9" - "@storybook/core" "5.3.9" - "@storybook/node-logger" "5.3.9" - "@svgr/webpack" "^4.0.3" - "@types/webpack-env" "^1.15.0" - babel-plugin-add-react-displayname "^0.0.5" - babel-plugin-named-asset-import "^0.3.1" - babel-plugin-react-docgen "^4.0.0" - core-js "^3.0.1" - global "^4.3.2" - lodash "^4.17.15" - mini-css-extract-plugin "^0.8.0" - prop-types "^15.7.2" - react-dev-utils "^9.0.0" - regenerator-runtime "^0.13.3" - semver "^6.0.0" - ts-dedent "^1.1.0" - webpack "^4.33.0" - "@storybook/router@5.3.9": version "5.3.9" resolved "https://registry.yarnpkg.com/@storybook/router/-/router-5.3.9.tgz#3c6e01f4dced9de8e8c5c314352fdc437f2441c2" @@ -7311,109 +6881,6 @@ ts-dedent "^1.1.0" webpack "^4.33.0" -"@svgr/babel-plugin-add-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-4.2.0.tgz#dadcb6218503532d6884b210e7f3c502caaa44b1" - integrity sha512-j7KnilGyZzYr/jhcrSYS3FGWMZVaqyCG0vzMCwzvei0coIkczuYMcniK07nI0aHJINciujjH11T72ICW5eL5Ig== - -"@svgr/babel-plugin-remove-jsx-attribute@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-4.2.0.tgz#297550b9a8c0c7337bea12bdfc8a80bb66f85abc" - integrity sha512-3XHLtJ+HbRCH4n28S7y/yZoEQnRpl0tvTZQsHqvaeNXPra+6vE5tbRliH3ox1yZYPCxrlqaJT/Mg+75GpDKlvQ== - -"@svgr/babel-plugin-remove-jsx-empty-expression@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-4.2.0.tgz#c196302f3e68eab6a05e98af9ca8570bc13131c7" - integrity sha512-yTr2iLdf6oEuUE9MsRdvt0NmdpMBAkgK8Bjhl6epb+eQWk6abBaX3d65UZ3E3FWaOwePyUgNyNCMVG61gGCQ7w== - -"@svgr/babel-plugin-replace-jsx-attribute-value@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-4.2.0.tgz#310ec0775de808a6a2e4fd4268c245fd734c1165" - integrity sha512-U9m870Kqm0ko8beHawRXLGLvSi/ZMrl89gJ5BNcT452fAjtF2p4uRzXkdzvGJJJYBgx7BmqlDjBN/eCp5AAX2w== - -"@svgr/babel-plugin-svg-dynamic-title@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-4.3.3.tgz#2cdedd747e5b1b29ed4c241e46256aac8110dd93" - integrity sha512-w3Be6xUNdwgParsvxkkeZb545VhXEwjGMwExMVBIdPQJeyMQHqm9Msnb2a1teHBqUYL66qtwfhNkbj1iarCG7w== - -"@svgr/babel-plugin-svg-em-dimensions@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-4.2.0.tgz#9a94791c9a288108d20a9d2cc64cac820f141391" - integrity sha512-C0Uy+BHolCHGOZ8Dnr1zXy/KgpBOkEUYY9kI/HseHVPeMbluaX3CijJr7D4C5uR8zrc1T64nnq/k63ydQuGt4w== - -"@svgr/babel-plugin-transform-react-native-svg@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-4.2.0.tgz#151487322843359a1ca86b21a3815fd21a88b717" - integrity sha512-7YvynOpZDpCOUoIVlaaOUU87J4Z6RdD6spYN4eUb5tfPoKGSF9OG2NuhgYnq4jSkAxcpMaXWPf1cePkzmqTPNw== - -"@svgr/babel-plugin-transform-svg-component@^4.2.0": - version "4.2.0" - resolved "https://registry.yarnpkg.com/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-4.2.0.tgz#5f1e2f886b2c85c67e76da42f0f6be1b1767b697" - integrity sha512-hYfYuZhQPCBVotABsXKSCfel2slf/yvJY8heTVX1PCTaq/IgASq1IyxPPKJ0chWREEKewIU/JMSsIGBtK1KKxw== - -"@svgr/babel-preset@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/babel-preset/-/babel-preset-4.3.3.tgz#a75d8c2f202ac0e5774e6bfc165d028b39a1316c" - integrity sha512-6PG80tdz4eAlYUN3g5GZiUjg2FMcp+Wn6rtnz5WJG9ITGEF1pmFdzq02597Hn0OmnQuCVaBYQE1OVFAnwOl+0A== - dependencies: - "@svgr/babel-plugin-add-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-attribute" "^4.2.0" - "@svgr/babel-plugin-remove-jsx-empty-expression" "^4.2.0" - "@svgr/babel-plugin-replace-jsx-attribute-value" "^4.2.0" - "@svgr/babel-plugin-svg-dynamic-title" "^4.3.3" - "@svgr/babel-plugin-svg-em-dimensions" "^4.2.0" - "@svgr/babel-plugin-transform-react-native-svg" "^4.2.0" - "@svgr/babel-plugin-transform-svg-component" "^4.2.0" - -"@svgr/core@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/core/-/core-4.3.3.tgz#b37b89d5b757dc66e8c74156d00c368338d24293" - integrity sha512-qNuGF1QON1626UCaZamWt5yedpgOytvLj5BQZe2j1k1B8DUG4OyugZyfEwBeXozCUwhLEpsrgPrE+eCu4fY17w== - dependencies: - "@svgr/plugin-jsx" "^4.3.3" - camelcase "^5.3.1" - cosmiconfig "^5.2.1" - -"@svgr/hast-util-to-babel-ast@^4.3.2": - version "4.3.2" - resolved "https://registry.yarnpkg.com/@svgr/hast-util-to-babel-ast/-/hast-util-to-babel-ast-4.3.2.tgz#1d5a082f7b929ef8f1f578950238f630e14532b8" - integrity sha512-JioXclZGhFIDL3ddn4Kiq8qEqYM2PyDKV0aYno8+IXTLuYt6TOgHUbUAAFvqtb0Xn37NwP0BTHglejFoYr8RZg== - dependencies: - "@babel/types" "^7.4.4" - -"@svgr/plugin-jsx@^4.3.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa" - integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w== - dependencies: - "@babel/core" "^7.4.5" - "@svgr/babel-preset" "^4.3.3" - "@svgr/hast-util-to-babel-ast" "^4.3.2" - svg-parser "^2.0.0" - -"@svgr/plugin-svgo@^4.3.1": - version "4.3.1" - resolved "https://registry.yarnpkg.com/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32" - integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w== - dependencies: - cosmiconfig "^5.2.1" - merge-deep "^3.0.2" - svgo "^1.2.2" - -"@svgr/webpack@^4.0.3": - version "4.3.3" - resolved "https://registry.yarnpkg.com/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" - integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== - dependencies: - "@babel/core" "^7.4.5" - "@babel/plugin-transform-react-constant-elements" "^7.0.0" - "@babel/preset-env" "^7.4.5" - "@babel/preset-react" "^7.0.0" - "@svgr/core" "^4.3.3" - "@svgr/plugin-jsx" "^4.3.3" - "@svgr/plugin-svgo" "^4.3.1" - loader-utils "^1.2.3" - "@swc/core-darwin-arm64@1.3.70": version "1.3.70" resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.70.tgz#056ac6899e22cb7f7be21388d4d938ca5123a72b" @@ -7480,13 +6947,6 @@ "@swc/core-win32-ia32-msvc" "1.3.70" "@swc/core-win32-x64-msvc" "1.3.70" -"@swc/helpers@0.4.11": - version "0.4.11" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.11.tgz#db23a376761b3d31c26502122f349a21b592c8de" - integrity sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw== - dependencies: - tslib "^2.4.0" - "@swc/helpers@^0.4.12": version "0.4.14" resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74" @@ -7793,11 +7253,6 @@ resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" integrity sha512-KEIlhXnIutzKwRbQkGWb/I4HFqBuUykAdHgDED6xqwXJfONCjF5VoE0cXEiurh3XauygxzeDzgtXUqvLkxFzzA== -"@types/fbemitter@^2.0.32": - version "2.0.32" - resolved "https://registry.yarnpkg.com/@types/fbemitter/-/fbemitter-2.0.32.tgz#8ed204da0f54e9c8eaec31b1eec91e25132d082c" - integrity sha1-jtIE2g9U6cjq7DGx7skeJRMtCCw= - "@types/fs-extra@^9.0.13": version "9.0.13" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.13.tgz#7594fbae04fe7f1918ce8b3d213f74ff44ac1f45" @@ -7831,11 +7286,6 @@ dependencies: "@types/node" "*" -"@types/hammerjs@^2.0.36": - version "2.0.41" - resolved "https://registry.yarnpkg.com/@types/hammerjs/-/hammerjs-2.0.41.tgz#f6ecf57d1b12d2befcce00e928a6a097c22980aa" - integrity sha512-ewXv/ceBaJprikMcxCmWU1FKyMAQ2X7a9Gtmzw8fcg2kIePI1crERDM818W+XYrxqdBBOdlf2rm137bU+BltCA== - "@types/hast@^2.0.0": version "2.3.4" resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" @@ -7876,11 +7326,6 @@ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz#0ea7b61496902b95890dc4c3a116b60cb8dae812" integrity sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ== -"@types/invariant@^2.2.29", "@types/invariant@^2.2.30": - version "2.2.35" - resolved "https://registry.yarnpkg.com/@types/invariant/-/invariant-2.2.35.tgz#cd3ebf581a6557452735688d8daba6cf0bd5a3be" - integrity sha512-DxX1V9P8zdJPYQat1gHyY0xj3efl8gnMVjiM9iCY6y27lj+PoQWkgjt8jDqmovPqULkKVpKRg8J36iQiA+EtEg== - "@types/is-function@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@types/is-function/-/is-function-1.0.0.tgz#1b0b819b1636c7baf0d6785d030d12edf70c3e83" @@ -7987,18 +7432,6 @@ resolved "https://registry.yarnpkg.com/@types/lockfile/-/lockfile-1.0.2.tgz#3f77e84171a2b7e3198bd5717c7547a54393baf8" integrity sha512-jD5VbvhfMhaYN4M3qPJuhMVUg3Dfc4tvPvLEAXn6GXbs/ajDFtCQahX37GIE65ipTI3I+hEvNaXS3MYAn9Ce3Q== -"@types/lodash.zipobject@^4.1.4": - version "4.1.6" - resolved "https://registry.yarnpkg.com/@types/lodash.zipobject/-/lodash.zipobject-4.1.6.tgz#75e140f44ac7d7682a18d3aae8ee4594fad094d7" - integrity sha512-30khEHqHWaLgMZR35wtkg07OmHiNiDQyor0SK7oj8Sy05tg6jDjPmJybeZ64WKeFZUEgs1tdJwdT0xUl+2qUgQ== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.178" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - "@types/markdown-it@^12.2.3": version "12.2.3" resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-12.2.3.tgz#0d6f6e5e413f8daaa26522904597be3d6cd93b51" @@ -8114,7 +7547,7 @@ resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df" integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ== -"@types/qs@^6.5.1", "@types/qs@^6.5.3": +"@types/qs@^6.5.3": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== @@ -8159,13 +7592,6 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-slick@^0.23.4": - version "0.23.8" - resolved "https://registry.yarnpkg.com/@types/react-slick/-/react-slick-0.23.8.tgz#91654e657158da57f082c7b213e20756d3a37502" - integrity sha512-SfzSg++/3uyftVZaCgHpW+2fnJFsyJEQ/YdsuqfOWQ5lqUYV/gY/UwAnkw4qksCj5jalto/T5rKXJ8zeFldQeA== - dependencies: - "@types/react" "*" - "@types/react-syntax-highlighter@11.0.2": version "11.0.2" resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.2.tgz#a2e3ff657d7c47813f80ca930f3d959c31ec51e3" @@ -8410,11 +7836,6 @@ anymatch "^3.0.0" source-map "^0.6.0" -"@types/websql@^0.0.27": - version "0.0.27" - resolved "https://registry.yarnpkg.com/@types/websql/-/websql-0.0.27.tgz#621a666a7f02018e7cbb4abab956a25736c27d71" - integrity sha1-Yhpman8CAY58u0q6uVaiVzbCfXE= - "@types/write-file-atomic@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/write-file-atomic/-/write-file-atomic-4.0.0.tgz#ffcedcb1ae027e0a28ddfe218b72b3573797b5bc" @@ -8666,22 +8087,6 @@ "@typescript-eslint/types" "5.9.0" eslint-visitor-keys "^3.0.0" -"@unimodules/core@~5.1.0": - version "5.1.2" - resolved "https://registry.yarnpkg.com/@unimodules/core/-/core-5.1.2.tgz#44de60184c9a50cf57bc8ec1cd024810a72ecf3e" - integrity sha512-iCWEbzsNHqDfL6p8FyCGPnL2EW7vdgMJsNNSlWtM/gl8kePdqZMI7aOxTC4cdRS2xm0wzxuDBtpfJkzZsKINZg== - dependencies: - compare-versions "^3.4.0" - -"@unimodules/react-native-adapter@~5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@unimodules/react-native-adapter/-/react-native-adapter-5.1.1.tgz#bb67a021c722772e716eaa3817084cd988642e4e" - integrity sha512-PlP6QQ2Z3ckORhS07tWcIweK+CkkxyzitJ1j1FD+N+G7G/CB99/vSfCEQ7BFVAPRO5vPrcS2QcwSDgvz06wKVA== - dependencies: - invariant "^2.2.4" - lodash "^4.5.0" - prop-types "^15.6.1" - "@vscode/emmet-helper@^2.8.4": version "2.8.4" resolved "https://registry.yarnpkg.com/@vscode/emmet-helper/-/emmet-helper-2.8.4.tgz#ab937e3ce79b0873c604d1ad50a9eeb7abae2937" @@ -9733,23 +9138,11 @@ acorn@^8.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== -add-dom-event-listener@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/add-dom-event-listener/-/add-dom-event-listener-1.1.0.tgz#6a92db3a0dd0abc254e095c0f1dc14acbbaae310" - integrity sha512-WCxx1ixHT0GQU9hb0KI/mhgRQhnU+U3GvwY6ZvVjYq8rsihIGoaIOUbY0yMPBxLH5MDtr0kz3fisWGNcbWW7Jw== - dependencies: - object-assign "4.x" - add-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= -add@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/add/-/add-2.0.6.tgz#248f0a9f6e5a528ef2295dbeec30532130ae2235" - integrity sha1-JI8Kn25aUo7yKV2+7DBTITCuIjU= - address@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" @@ -9885,7 +9278,7 @@ ajv@^8.0.1: semver "^5.1.0" tunnel-agent "^0.6.0" -algoliasearch@4, algoliasearch@4.14.3, "algoliasearch@>= 3.27.1 < 5": +algoliasearch@4, algoliasearch@4.14.3: version "4.14.3" resolved "https://registry.yarnpkg.com/algoliasearch/-/algoliasearch-4.14.3.tgz#f02a77a4db17de2f676018938847494b692035e7" integrity sha512-GZTEuxzfWbP/vr7ZJfGzIl8fOsoxN916Z6FY2Egc9q2TmZ6hvq5KfAxY89pPW01oW/2HDEKA8d30f9iAH9eXYg== @@ -9966,13 +9359,6 @@ ansi-align@^3.0.0, ansi-align@^3.0.1: dependencies: string-width "^4.1.0" -ansi-colors@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-1.1.0.tgz#6374b4dd5d4718ff3ce27a671a3b1cad077132a9" - integrity sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA== - dependencies: - ansi-wrap "^0.1.0" - ansi-colors@^3.0.0: version "3.2.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" @@ -9983,13 +9369,6 @@ ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-cyan@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-cyan/-/ansi-cyan-0.1.1.tgz#538ae528af8982f28ae30d86f2f17456d2609873" - integrity sha1-U4rlKK+JgvKK4w2G8vF0VtJgmHM= - dependencies: - ansi-wrap "0.1.0" - ansi-escape-sequences@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-escape-sequences/-/ansi-escape-sequences-4.1.0.tgz#2483c8773f50dd9174dd9557e92b1718f1816097" @@ -9997,11 +9376,6 @@ ansi-escape-sequences@^4.0.0: dependencies: array-back "^3.0.1" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - integrity sha1-06ioOzGapneTZisT52HHkRQiMG4= - ansi-escapes@^3.0.0, ansi-escapes@^3.1.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" @@ -10023,13 +9397,6 @@ ansi-fragments@^0.2.1: slice-ansi "^2.0.0" strip-ansi "^5.0.0" -ansi-gray@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" - integrity sha1-KWLPVOyXksSFEKPetSRDaGHvclE= - dependencies: - ansi-wrap "0.1.0" - ansi-html-community@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41" @@ -10040,13 +9407,6 @@ ansi-html@0.0.7: resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= -ansi-red@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ansi-red/-/ansi-red-0.1.1.tgz#8c638f9d1080800a353c9c28c8a81ca4705d946c" - integrity sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow== - dependencies: - ansi-wrap "0.1.0" - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" @@ -10057,7 +9417,7 @@ ansi-regex@^3.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= -ansi-regex@^4.0.0, ansi-regex@^4.1.0: +ansi-regex@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== @@ -10109,69 +9469,6 @@ ansi-to-html@^0.6.11: dependencies: entities "^1.1.1" -ansi-wrap@0.1.0, ansi-wrap@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ansi-wrap/-/ansi-wrap-0.1.0.tgz#a82250ddb0015e9a27ca82e82ea603bbfa45efaf" - integrity sha1-qCJQ3bABXponyoLoLqYDu/pF768= - -antd@3.23.2: - version "3.23.2" - resolved "https://registry.yarnpkg.com/antd/-/antd-3.23.2.tgz#6fcbe5b22a932913a33dce0b6b76b4a60c30a403" - integrity sha512-S62EvyxPV0IoFR650qtCjUy2E7nY3JkxTP1t71LER09DTTK4fJGw4wWhalNCjkIHR2hPHWGfu0MSHocov3F4dw== - dependencies: - "@ant-design/create-react-context" "^0.2.4" - "@ant-design/icons" "~2.1.1" - "@ant-design/icons-react" "~2.0.1" - "@types/react-slick" "^0.23.4" - array-tree-filter "^2.1.0" - babel-runtime "6.x" - classnames "~2.2.6" - copy-to-clipboard "^3.2.0" - css-animation "^1.5.0" - dom-closest "^0.2.0" - enquire.js "^2.1.6" - lodash "^4.17.13" - moment "^2.24.0" - omit.js "^1.0.2" - prop-types "^15.7.2" - raf "^3.4.1" - rc-animate "^2.8.3" - rc-calendar "~9.15.5" - rc-cascader "~0.17.4" - rc-checkbox "~2.1.6" - rc-collapse "~1.11.3" - rc-dialog "~7.5.2" - rc-drawer "~2.0.1" - rc-dropdown "~2.4.1" - rc-editor-mention "^1.1.13" - rc-form "^2.4.5" - rc-input-number "~4.5.0" - rc-mentions "~0.4.0" - rc-menu "~7.4.23" - rc-notification "~3.3.1" - rc-pagination "~1.20.5" - rc-progress "~2.5.0" - rc-rate "~2.5.0" - rc-select "~9.2.0" - rc-slider "~8.6.11" - rc-steps "~3.5.0" - rc-switch "~1.9.0" - rc-table "~6.7.0" - rc-tabs "~9.6.4" - rc-time-picker "~3.7.1" - rc-tooltip "~3.7.3" - rc-tree "~2.1.0" - rc-tree-select "~2.9.1" - rc-trigger "^2.6.2" - rc-upload "~2.7.0" - rc-util "^4.10.0" - react-lazy-load "^3.0.13" - react-lifecycles-compat "^3.0.4" - react-slick "~0.25.2" - resize-observer-polyfill "^1.5.1" - shallowequal "^1.1.0" - warning "~4.0.3" - any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -10309,11 +9606,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -argsarray@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" - integrity sha1-bnIHtOzbObCviDA/pa4ivajfYcs= - aria-query@^4.2.2: version "4.2.2" resolved "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -10327,29 +9619,16 @@ aria-query@^5.0.0: resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.0.0.tgz#210c21aaf469613ee8c9a62c7f86525e058db52c" integrity sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg== -arr-diff@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-1.1.0.tgz#687c32758163588fef7de7b36fabe495eb1a399a" - integrity sha1-aHwydYFjWI/vfeezb6vklesaOZo= - dependencies: - arr-flatten "^1.0.1" - array-slice "^0.2.3" - arr-diff@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= -arr-flatten@^1.0.1, arr-flatten@^1.1.0: +arr-flatten@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== -arr-union@^2.0.1: - version "2.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-2.1.0.tgz#20f9eab5ec70f5c7d215b1077b1c39161d292c7d" - integrity sha1-IPnqtexw9cfSFbEHexw5Fh0pLH0= - arr-union@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" @@ -10455,16 +9734,6 @@ array-reduce@~0.0.0: resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" integrity sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys= -array-slice@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" - integrity sha1-3Tz7gO15c6dRF82sabC5nshhhvU= - -array-tree-filter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190" - integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw== - array-union@^1.0.1, array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -10539,11 +9808,6 @@ arrify@^2.0.1: resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== -art@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/art/-/art-0.10.3.tgz#b01d84a968ccce6208df55a733838c96caeeaea2" - integrity sha512-HXwbdofRTiJT6qZX/FnchtldzJjS3vkLJxQilc3Xj+ma2MXjY4UAyQ0ls1XZYVnDvVIBiFZbC6QsvtW86TD6tQ== - asap@^2.0.0, asap@~2.0.3, asap@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" @@ -10598,7 +9862,7 @@ ast-types@0.13.2: resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.2.tgz#df39b677a911a83f3a049644fb74fdded23cea48" integrity sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA== -ast-types@0.14.2, ast-types@^0.14.1, ast-types@^0.14.2: +ast-types@0.14.2, ast-types@^0.14.1: version "0.14.2" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.14.2.tgz#600b882df8583e3cd4f2df5fa20fa83759d4bdfd" integrity sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA== @@ -10708,11 +9972,6 @@ async-retry@^1.1.4: dependencies: retry "0.12.0" -async-validator@~1.11.3: - version "1.11.5" - resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-1.11.5.tgz#9d43cf49ef6bb76be5442388d19fb9a6e47597ea" - integrity sha512-XNtCsMAeAH1pdLMEg1z8/Bb3a8cdCbui9QbJATRFHHHW5kT6+NPI3zSVQUXgikTFITzsg+kYY5NTWhM2Orwt9w== - async@^1.3.0, async@^1.4.2, async@~1.5: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -10959,7 +10218,7 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-jest@24.9.0, babel-jest@^24.7.1, babel-jest@^24.9.0: +babel-jest@24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== @@ -11106,15 +10365,6 @@ babel-plugin-macros@^2.0.0, babel-plugin-macros@^2.7.0: cosmiconfig "^6.0.0" resolve "^1.12.0" -babel-plugin-macros@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1" - integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg== - dependencies: - "@babel/runtime" "^7.12.5" - cosmiconfig "^7.0.0" - resolve "^1.19.0" - babel-plugin-minify-builtins@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.5.0.tgz#31eb82ed1a0d0efdc31312f93b6e4741ce82c36b" @@ -11191,7 +10441,7 @@ babel-plugin-minify-type-constructors@^0.4.3: dependencies: babel-helper-is-void-0 "^0.4.3" -babel-plugin-module-resolver@3.2.0, babel-plugin-module-resolver@^3.2.0: +babel-plugin-module-resolver@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-3.2.0.tgz#ddfa5e301e3b9aa12d852a9979f18b37881ff5a7" integrity sha512-tjR0GvSndzPew/Iayf4uICWZqjBwnlMWjSx6brryfQ81F9rxBVqwDJtFCV8oOs0+vJeefK9TmdZtkIFdFe1UnA== @@ -11213,11 +10463,6 @@ babel-plugin-module-resolver@^4.1.0: reselect "^4.0.0" resolve "^1.13.1" -babel-plugin-named-asset-import@^0.3.1: - version "0.3.8" - resolved "https://registry.yarnpkg.com/babel-plugin-named-asset-import/-/babel-plugin-named-asset-import-0.3.8.tgz#6b7fa43c59229685368683c28bc9734f24524cc2" - integrity sha512-WXiAc++qo7XcJ1ZnTYGtLxmBCVbddAml3CEXgWaBzNzLNoxtQ8AiGEFDMOhot9XjTCQbvP5E77Fj9Gk924f00Q== - babel-plugin-polyfill-corejs2@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz#e9124785e6fd94f94b618a7954e5693053bf5327" @@ -11273,20 +10518,6 @@ babel-plugin-polyfill-regenerator@^0.4.1: dependencies: "@babel/helper-define-polyfill-provider" "^0.3.3" -babel-plugin-react-docgen@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/babel-plugin-react-docgen/-/babel-plugin-react-docgen-4.2.1.tgz#7cc8e2f94e8dc057a06e953162f0810e4e72257b" - integrity sha512-UQ0NmGHj/HAqi5Bew8WvNfCk8wSsmdgNd8ZdMjBCICtyCJCq9LiqgqvjCYe570/Wg7AQArSq1VQ60Dd/CHN7mQ== - dependencies: - ast-types "^0.14.2" - lodash "^4.17.15" - react-docgen "^5.0.0" - -babel-plugin-react-native-web@^0.11.7: - version "0.11.7" - resolved "https://registry.yarnpkg.com/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.11.7.tgz#15b578c0731bd7d65d334f9c759d95e8e4a602e2" - integrity sha512-CxE7uhhqkzAFkwV2X7+Mc/UVPujQQDtja/EGxCXRJvdYRi72QTmaJYKbK1lV9qgTZuB+TDguU89coaA9Z1BNbg== - babel-plugin-react-native-web@~0.17.1: version "0.17.5" resolved "https://registry.yarnpkg.com/babel-plugin-react-native-web/-/babel-plugin-react-native-web-0.17.5.tgz#4bce51a20d21839f20506ef184bd5743a2c6d067" @@ -11336,7 +10567,7 @@ babel-plugin-transform-react-pure-class-to-function@1.0.1: dependencies: babel-helper-is-react-class "^1.0.0" -babel-plugin-transform-react-remove-prop-types@0.4.24, babel-plugin-transform-react-remove-prop-types@^0.4.24: +babel-plugin-transform-react-remove-prop-types@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/babel-plugin-transform-react-remove-prop-types/-/babel-plugin-transform-react-remove-prop-types-0.4.24.tgz#f2edaf9b4c6a5fbe5c1d678bfb531078c1555f3a" integrity sha512-eqj0hVcJUR57/Ug2zE1Yswsw4LhuqqHhD+8v120T1cl3kjg76QwtyBrdIk4WVwK+lAhBJVYCd/v+4nc4y+8JsA== @@ -11387,15 +10618,6 @@ babel-plugin-transform-vue-jsx@^3.5.0: dependencies: esutils "^2.0.2" -babel-polyfill@6.23.0: - version "6.23.0" - resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" - integrity sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0= - dependencies: - babel-runtime "^6.22.0" - core-js "^2.4.0" - regenerator-runtime "^0.10.0" - babel-preset-current-node-syntax@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" @@ -11414,28 +10636,6 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-expo@8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-8.1.0.tgz#7dfdebe6dad80edd1901e0f733ca6a6cce2ad605" - integrity sha512-ZlGIo8OlO0b7S//QrqHGIIf2BY9HId5efxgBxyic5ZbKo6NHICThjSpEz4rRyQRGka7HixBq/Jyjsn4M2D/n/g== - dependencies: - "@babel/plugin-proposal-decorators" "^7.6.0" - "@babel/preset-env" "^7.6.3" - babel-plugin-module-resolver "^3.2.0" - babel-plugin-react-native-web "^0.11.7" - metro-react-native-babel-preset "^0.56.0" - -babel-preset-expo@~8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-8.1.1.tgz#7b6bd561ee598197c7f49572c85f3f45df94d57e" - integrity sha512-73VtU6+IsOPMHsXIXHJTycoAmE9hDCvWY2E14E3sVL/EhOJsH3YbWirRTiUiklfEMAEaOxBRc4C4GxqGmaFjxQ== - dependencies: - "@babel/plugin-proposal-decorators" "^7.6.0" - "@babel/preset-env" "^7.6.3" - babel-plugin-module-resolver "^3.2.0" - babel-plugin-react-native-web "^0.11.7" - metro-react-native-babel-preset "^0.56.0" - babel-preset-expo@~9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/babel-preset-expo/-/babel-preset-expo-9.0.2.tgz#018bafbe29c61491d55bf5c1b603534b54a13bf1" @@ -11448,7 +10648,7 @@ babel-preset-expo@~9.0.2: babel-plugin-react-native-web "~0.17.1" metro-react-native-babel-preset "~0.64.0" -babel-preset-fbjs@^3.1.2, babel-preset-fbjs@^3.2.0, babel-preset-fbjs@^3.3.0: +babel-preset-fbjs@^3.3.0: version "3.4.0" resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" integrity sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow== @@ -11526,28 +10726,6 @@ babel-preset-jest@^27.4.0: babel-plugin-transform-undefined-to-void "^6.9.4" lodash "^4.17.11" -babel-preset-react-app@10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-react-app/-/babel-preset-react-app-10.0.1.tgz#ed6005a20a24f2c88521809fa9aea99903751584" - integrity sha512-b0D9IZ1WhhCWkrTXyFuIIgqGzSkRIH5D5AmB0bXbzYAB1OBAwHcUeyWW2LorutLWF5btNo/N7r/cIdmvvKJlYg== - dependencies: - "@babel/core" "^7.16.0" - "@babel/plugin-proposal-class-properties" "^7.16.0" - "@babel/plugin-proposal-decorators" "^7.16.4" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.0" - "@babel/plugin-proposal-numeric-separator" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.0" - "@babel/plugin-proposal-private-methods" "^7.16.0" - "@babel/plugin-transform-flow-strip-types" "^7.16.0" - "@babel/plugin-transform-react-display-name" "^7.16.0" - "@babel/plugin-transform-runtime" "^7.16.4" - "@babel/preset-env" "^7.16.4" - "@babel/preset-react" "^7.16.0" - "@babel/preset-typescript" "^7.16.0" - "@babel/runtime" "^7.16.3" - babel-plugin-macros "^3.1.0" - babel-plugin-transform-react-remove-prop-types "^0.4.24" - babel-preset-vue@2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/babel-preset-vue/-/babel-preset-vue-2.0.2.tgz#cfadf1bd736125397481b5f8525ced0049a0c71f" @@ -11572,7 +10750,7 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@6.x, babel-runtime@^6.22.0, babel-runtime@^6.23.0, babel-runtime@^6.26.0: +babel-runtime@^6.22.0, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -11626,11 +10804,6 @@ backo2@^1.0.2: resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" integrity sha1-MasayLEpNjRj41s+u2n038+6eUc= -badgin@^1.1.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/badgin/-/badgin-1.2.3.tgz#994b5f519827d7d5422224825b2c8faea2bc43ad" - integrity sha512-NQGA7LcfCpSzIbGRbkgjgdWkjy7HI+Th5VLxTJfW5EeaAf3fnS+xWQaQOCYiny+q6QSvxqoSO04vCx+4u++EJw== - bail@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.4.tgz#7181b66d508aa3055d3f6c13f0a0c720641dde9b" @@ -12032,7 +11205,7 @@ browser-process-hrtime@^1.0.0: resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== -browser-resolve@^1.11.0, browser-resolve@^1.11.3, browser-resolve@^1.7.0: +browser-resolve@^1.11.0, browser-resolve@^1.7.0: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== @@ -12348,24 +11521,6 @@ bytes@3.1.2, bytes@^3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== -c8@^7.6.0: - version "7.12.0" - resolved "https://registry.yarnpkg.com/c8/-/c8-7.12.0.tgz#402db1c1af4af5249153535d1c84ad70c5c96b14" - integrity sha512-CtgQrHOkyxr5koX1wEUmN/5cfDa2ckbHRA4Gy5LAL0zaCFtVWJS5++n+w4/sr2GWGerBxgTjpKeDclk/Qk6W/A== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@istanbuljs/schema" "^0.1.3" - find-up "^5.0.0" - foreground-child "^2.0.0" - istanbul-lib-coverage "^3.2.0" - istanbul-lib-report "^3.0.0" - istanbul-reports "^3.1.4" - rimraf "^3.0.2" - test-exclude "^6.0.0" - v8-to-istanbul "^9.0.0" - yargs "^16.2.0" - yargs-parser "^20.2.9" - cac@^3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/cac/-/cac-3.0.4.tgz#6d24ceec372efe5c9b798808bc7f49b47242a4ef" @@ -12398,7 +11553,7 @@ cacache@^10.0.4: unique-filename "^1.1.0" y18n "^4.0.0" -cacache@^12.0.2, cacache@^12.0.3: +cacache@^12.0.2: version "12.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== @@ -12672,7 +11827,7 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo= -camelcase@^4.0.0, camelcase@^4.1.0: +camelcase@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= @@ -12702,7 +11857,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001179, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001426: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000981, caniuse-lite@^1.0.30000989, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001125, caniuse-lite@^1.0.30001179, caniuse-lite@^1.0.30001228, caniuse-lite@^1.0.30001332, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426: version "1.0.30001451" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz#2e197c698fc1373d63e1406d6607ea4617c613f1" integrity sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w== @@ -12763,24 +11918,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -"chainsaw@>=0.0.7 <0.1": - version "0.0.9" - resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.0.9.tgz#11a05102d1c4c785b6d0415d336d5a3a1612913e" - integrity sha1-EaBRAtHEx4W20EFdM21aOhYSkT4= - dependencies: - traverse ">=0.3.0 <0.4" - -chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" @@ -12823,6 +11960,17 @@ chalk@4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" @@ -12930,11 +12078,6 @@ character-reference-invalid@^2.0.0: resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== -chardet@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" - integrity sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I= - chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -13078,12 +12221,12 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.2.6, classnames@~2.2.6: +classnames@2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== -classnames@2.x, classnames@^2.2.0, classnames@^2.2.1, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6: +classnames@^2.2.5: version "2.3.1" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== @@ -13239,15 +12382,6 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" -cliui@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" - integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== - dependencies: - string-width "^2.1.1" - strip-ansi "^4.0.0" - wrap-ansi "^2.0.0" - cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -13284,17 +12418,6 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" -clone-deep@^0.2.4: - version "0.2.4" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" - integrity sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY= - dependencies: - for-own "^0.1.3" - is-plain-object "^2.0.1" - kind-of "^3.0.2" - lazy-cache "^1.0.3" - shallow-clone "^0.1.2" - clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -13596,23 +12719,11 @@ compare-versions@^3.4.0: resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== -component-classes@1.x, component-classes@^1.2.5, component-classes@^1.2.6: - version "1.2.6" - resolved "https://registry.yarnpkg.com/component-classes/-/component-classes-1.2.6.tgz#c642394c3618a4d8b0b8919efccbbd930e5cd691" - integrity sha1-xkI5TDYYpNiwuJGe/Mu9kw5c1pE= - dependencies: - component-indexof "0.0.3" - component-emitter@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6" integrity sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= -component-indexof@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/component-indexof/-/component-indexof-0.0.3.tgz#11d091312239eb8f32c8f25ae9cb002ffe8d3c24" - integrity sha1-EdCRMSI5648yyPJa6csAL/6NPCQ= - component-type@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" @@ -13653,7 +12764,7 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= -concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.0, concat-stream@^1.6.1: +concat-stream@1.6.2, concat-stream@^1.5.0, concat-stream@^1.6.1: version "1.6.2" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== @@ -13960,7 +13071,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.0.8, copy-to-clipboard@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== @@ -13981,24 +13092,6 @@ copy-webpack-plugin@^4.6.0: p-limit "^1.0.0" serialize-javascript "^1.4.0" -copy-webpack-plugin@^5.0.4: - version "5.1.2" - resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.2.tgz#8a889e1dcafa6c91c6cd4be1ad158f1d3823bae2" - integrity sha512-Uh7crJAco3AjBvgAy9Z75CjK8IG+gxaErro71THQ+vv/bl4HaQcpkexAY8KVW/T6D2W2IRr+couF/knIRkZMIQ== - dependencies: - cacache "^12.0.3" - find-cache-dir "^2.1.0" - glob-parent "^3.1.0" - globby "^7.1.1" - is-glob "^4.0.1" - loader-utils "^1.2.3" - minimatch "^3.0.4" - normalize-path "^3.0.0" - p-limit "^2.2.1" - schema-utils "^1.0.0" - serialize-javascript "^4.0.0" - webpack-log "^2.0.0" - copy-webpack-plugin@~6.0.3: version "6.0.4" resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-6.0.4.tgz#7b7d7f7f290aa21b3411d02525859b89988a200b" @@ -14028,7 +13121,7 @@ core-js-pure@^3.0.0, core-js-pure@^3.0.1: resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.3.tgz#10e9e3b2592ecaede4283e8f3ad7020811587c02" integrity sha512-V5qQZVAr9K0xu7jXg1M7qTEwuxUgqr7dUOezGaNa7i+Xn9oXAU/d1fzqD9ObuwpVQOaorO5s70ckyi1woP9lVA== -core-js@2, core-js@^2.2.2, core-js@^2.4.0, core-js@^2.4.1, core-js@^2.5.0, core-js@^2.6.12, core-js@^2.6.5: +core-js@2, core-js@^2.4.0, core-js@^2.5.0, core-js@^2.6.12, core-js@^2.6.5: version "2.6.12" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -14153,7 +13246,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -create-react-class@*, create-react-class@^15.5.1, create-react-class@^15.5.3, create-react-class@^15.6.2, create-react-class@^15.6.3, create-react-class@^15.7.0: +create-react-class@^15.7.0: version "15.7.0" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.7.0.tgz#7499d7ca2e69bb51d13faf59bd04f0c65a1d6c1e" integrity sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng== @@ -14216,7 +13309,7 @@ cross-spawn@^4.0.2: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^5.0.1, cross-spawn@^5.1.0: +cross-spawn@^5.0.1: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= @@ -14257,14 +13350,6 @@ crypto-random-string@^2.0.0: resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== -css-animation@1.x, css-animation@^1.3.2, css-animation@^1.5.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/css-animation/-/css-animation-1.6.1.tgz#162064a3b0d51f958b7ff37b3d6d4de18e17039e" - integrity sha512-/48+/BaEaHRY6kNQ2OIPzKf9A6g8WjZYjhiNDNuIVbsm5tXCGIAsHDjB4Xu1C4vXJtUWZo26O68OQkDpNBaPog== - dependencies: - babel-runtime "6.x" - component-classes "^1.2.5" - css-blank-pseudo@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/css-blank-pseudo/-/css-blank-pseudo-0.1.4.tgz#dfdefd3254bf8a82027993674ccf35483bfcb3c5" @@ -14324,7 +13409,7 @@ css-loader@^1.0.1: postcss-value-parser "^3.3.0" source-list-map "^2.0.0" -css-loader@^3.0.0, css-loader@^3.2.0, css-loader@~3.6.0: +css-loader@^3.0.0, css-loader@~3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.6.0.tgz#2e4b2c7e6e2d27f8c8f28f61bffcd2e6c91ef645" integrity sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ== @@ -14625,11 +13710,6 @@ cyclist@~0.2.2: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= -d3-array@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" - integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== - d3-array@^2.8.0: version "2.12.1" resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-2.12.1.tgz#e20b41aafcdffdf5d50928004ececf815a465e81" @@ -14712,11 +13792,6 @@ de-indent@^1.0.2: resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== -debounce@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - debug@2, debug@2.6.9, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -14813,13 +13888,6 @@ dedent@^0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= -deep-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-3.0.0.tgz#c8e4c4d401cba25550a2f0f486a2e75bc5f219a2" - integrity sha512-YX2i9XjJ7h5q/aQ/IM9PEwEnDqETAIYbggmdDB3HLTlSgo1CxPsj6pvhPG68rq6SVE0+p+6Ywsm5fTYNrYtBWw== - dependencies: - is-obj "^1.0.0" - deep-equal@^1.0.1, deep-equal@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.1.tgz#b5c98c942ceffaf7cb051e24e1434a25a2e6076a" @@ -15021,16 +14089,6 @@ deprecated-decorator@^0.1.6: resolved "https://registry.yarnpkg.com/deprecated-decorator/-/deprecated-decorator-0.1.6.tgz#00966317b7a12fe92f3cc831f7583af329b86c37" integrity sha1-AJZjF7ehL+kvPMgx91g68ym4bDc= -deprecated-react-native-listview@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/deprecated-react-native-listview/-/deprecated-react-native-listview-0.0.5.tgz#fc8a6dc45b0a8ba611e6014e13b38d6d763e763f" - integrity sha512-Cy7nDdd+KU+nR3tY1BSMuoZpsYC6OVSZyAiUSTDBop2lIgzCseDx7XI57x6h+NXer/8aor2yiQDQfeFcmBMwgQ== - dependencies: - create-react-class "*" - fbjs "*" - invariant "*" - react-clone-referenced-element "*" - deprecation@^2.0.0, deprecation@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" @@ -15101,11 +14159,6 @@ detect-libc@^1.0.2, detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -15153,16 +14206,6 @@ dezalgo@^1.0.0: asap "^2.0.0" wrappy "1" -didyoumean@^1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" - integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== - -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== - diff-sequences@^27.4.0: version "27.4.0" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.4.0.tgz#d783920ad8d06ec718a060d00196dfef25b132a5" @@ -15316,18 +14359,6 @@ dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9: resolved "https://registry.yarnpkg.com/dom-accessibility-api/-/dom-accessibility-api-0.5.14.tgz#56082f71b1dc7aac69d83c4285eef39c15d93f56" integrity sha512-NMt+m9zFMPZe0JcY9gN224Qvk6qLIdqex29clBvc/y75ZBX9YA9wNK3frsYvu2DI1xcCIwxwnX+TlsJ2DSOADg== -dom-align@^1.7.0: - version "1.12.2" - resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.2.tgz#0f8164ebd0c9c21b0c790310493cd855892acd4b" - integrity sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg== - -dom-closest@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/dom-closest/-/dom-closest-0.2.0.tgz#ebd9f91d1bf22e8d6f477876bbcd3ec90216c0cf" - integrity sha1-69n5HRvyLo1vR3h2u80+yQIWwM8= - dependencies: - dom-matches ">=1.0.1" - dom-converter@~0.1: version "0.1.4" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" @@ -15348,16 +14379,6 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" -dom-matches@>=1.0.1: - version "2.0.0" - resolved "https://registry.yarnpkg.com/dom-matches/-/dom-matches-2.0.0.tgz#d2728b416a87533980eb089b848d253cf23a758c" - integrity sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw= - -dom-scroll-into-view@1.x, dom-scroll-into-view@^1.2.0, dom-scroll-into-view@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e" - integrity sha1-6PNnMt0ImwIBqI14Fdw/iObWbH4= - dom-serializer@0: version "0.1.0" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" @@ -15564,15 +14585,6 @@ dotenv@~10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -draft-js@^0.10.0, draft-js@~0.10.0: - version "0.10.5" - resolved "https://registry.yarnpkg.com/draft-js/-/draft-js-0.10.5.tgz#bfa9beb018fe0533dbb08d6675c371a6b08fa742" - integrity sha512-LE6jSCV9nkPhfVX2ggcRLA4FKs6zWq9ceuO/88BpXdNCS7mjRTgs0NsV6piUCJX9YxMsB9An33wnkMmU2sD2Zg== - dependencies: - fbjs "^0.8.15" - immutable "~3.7.4" - object-assign "^4.1.0" - dset@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a" @@ -15789,11 +14801,6 @@ enhanced-resolve@^4.1.1, enhanced-resolve@^4.5.0: memory-fs "^0.5.0" tapable "^1.0.0" -enquire.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/enquire.js/-/enquire.js-2.1.6.tgz#3e8780c9b8b835084c3f60e166dbc3c2a3c89814" - integrity sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ= - enquirer@^2.3.5, enquirer@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" @@ -15852,7 +14859,7 @@ envify@^4.0.0: esprima "^4.0.0" through "~2.3.4" -envinfo@^7.1.0, envinfo@^7.7.2, envinfo@^7.7.4, envinfo@^7.8.1: +envinfo@^7.7.2, envinfo@^7.7.4, envinfo@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== @@ -16644,15 +15651,6 @@ estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== -estree-to-babel@^3.1.0: - version "3.2.1" - resolved "https://registry.yarnpkg.com/estree-to-babel/-/estree-to-babel-3.2.1.tgz#82e78315275c3ca74475fdc8ac1a5103c8a75bf5" - integrity sha512-YNF+mZ/Wu2FU/gvmzuWtYc8rloubL7wfXCTgouFrnjGVXPA/EeYYA7pupXWrb3Iv1cTBeSSxxJIbK23l4MRNqg== - dependencies: - "@babel/traverse" "^7.1.6" - "@babel/types" "^7.2.0" - c8 "^7.6.0" - estree-util-is-identifier-name@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.1.tgz#cf07867f42705892718d9d89eb2d85eaa8f0fcb5" @@ -16719,21 +15717,11 @@ eventemitter3@^2.0.3: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-2.0.3.tgz#b5e1079b59fb5e1ba2771c0a993be060a58c99ba" integrity sha1-teEHm1n7XhuidxwKmTvgYKWMmbo= -eventemitter3@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163" - integrity sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA== - eventemitter3@^4.0.0, eventemitter3@^4.0.4: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -eventlistener@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/eventlistener/-/eventlistener-0.0.1.tgz#ed2baabb852227af2bcf889152c72c63ca532eb8" - integrity sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg= - events@^1.1.0, events@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -16912,18 +15900,6 @@ expand-tilde@^2.0.0, expand-tilde@^2.0.2: dependencies: homedir-polyfill "^1.0.1" -expect@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" - integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== - dependencies: - "@jest/types" "^24.9.0" - ansi-styles "^3.2.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.9.0" - expect@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/expect/-/expect-27.4.6.tgz#f335e128b0335b6ceb4fcab67ece7cbd14c942e6" @@ -16939,17 +15915,6 @@ expo-application@~4.0.2: resolved "https://registry.yarnpkg.com/expo-application/-/expo-application-4.0.2.tgz#860dbd12132a56de7cf75fe7b5146b6cd97ed30e" integrity sha512-ngTaFplTkWn0X45gMC+VNXGyJfGxX4wOwKmtr17rNMVWOQUhhLlyMkTj9bAamzsuwZh35l3S/eD/N1aMWWUwMw== -expo-asset@~8.1.3: - version "8.1.7" - resolved "https://registry.yarnpkg.com/expo-asset/-/expo-asset-8.1.7.tgz#32618e51f85df56f1d7dd54c71eb486ae7f7674e" - integrity sha512-g0+a+Uc+GfOI7VtZ6d0WB78qq6Lu3vKqHN3TBfcsndcx893CSmo6ZVLcrlL9evdZwlbSO+9zLrLdzEw38a/gMA== - dependencies: - blueimp-md5 "^2.10.0" - invariant "^2.2.4" - md5-file "^3.2.3" - path-browserify "^1.0.0" - url-parse "^1.4.4" - expo-asset@~8.4.6: version "8.4.6" resolved "https://registry.yarnpkg.com/expo-asset/-/expo-asset-8.4.6.tgz#1c40e9badac66dbd3d2be2810711937e5b9b09bd" @@ -17033,16 +15998,6 @@ expo-constants@~13.0.2: "@expo/config" "^6.0.6" uuid "^3.3.2" -expo-constants@~9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-9.0.0.tgz#35c600079ee91d38fe4f56375caae6e90f122fdd" - integrity sha512-1kqZMM8Ez5JT3sTEx8I69fP6NYFLOJjeM6Z63dD/m2NiwvzSADiO5+BhghnWNGN1L3bxbgOjXS6EHtS7CdSfxA== - -expo-error-recovery@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/expo-error-recovery/-/expo-error-recovery-1.1.0.tgz#98b9de5400dbfd022d1631739f3bf5e7016565da" - integrity sha512-33aRfPaXdAt0df1TL26JjM5qCAoEW8RAExjgMgunPcdQcf4sWiWFm3qYL8zrO/8DM4uUq4X2FCuPLHMlOYT/aw== - expo-error-recovery@~3.0.5: version "3.0.5" resolved "https://registry.yarnpkg.com/expo-error-recovery/-/expo-error-recovery-3.0.5.tgz#1802b733e998606a8fcfb0abe6682c334319ef75" @@ -17056,13 +16011,6 @@ expo-file-system@~13.1.3: "@expo/config-plugins" "^4.0.2" uuid "^3.4.0" -expo-file-system@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-file-system/-/expo-file-system-8.1.0.tgz#d6aa66fa32c19982b94d0013f963c5ee972dfd6d" - integrity sha512-xb4roeU8CotW8t3LkmsrliNbgFpY2KB+3sW1NnujnH39pFVwCd/kfujCYzRauj8aUy/HhSq+3xGkQTpC7pSjVw== - dependencies: - uuid "^3.4.0" - expo-font@~10.0.5: version "10.0.5" resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-10.0.5.tgz#8010060ec5326b3b462f7a1ac6b232dc4d1a7317" @@ -17070,36 +16018,11 @@ expo-font@~10.0.5: dependencies: fontfaceobserver "^2.1.0" -expo-font@~8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/expo-font/-/expo-font-8.1.1.tgz#40de629d7332887bdafae4756741f6979fc0043e" - integrity sha512-z6008K7YSA7wpJ1mNyG2eSYUhEoFVjdL2uAbwaHFpsqwxDS4tcdKHoWkanIUiEnsjtHK7Uk0ywKJ8MRzmCaklw== - dependencies: - fbjs "1.0.0" - fontfaceobserver "^2.1.0" - expo-keep-awake@~10.0.2: version "10.0.2" resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-10.0.2.tgz#706bda839782bb3e8ad4cbe43bde471a56368813" integrity sha512-Ro1lgyKldbFs4mxhWM+goX9sg0S2SRR8FiJJeOvaRzf8xNhrZfWA00Zpr+/3ocCoWQ3eEL+X9UF4PXXHf0KoOg== -expo-keep-awake@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-8.1.0.tgz#3a1d8aa5a8395d40c7d79e1c93020ae5f848e664" - integrity sha512-RNPwWvpwsJwJS8ZI1yklKyVQ6l2NNZBCN2aSgQMRza2SABnpFFzDLHQwMo7DC+nbmrOueMvCIDr0VI3xrzGfEg== - -expo-linear-gradient@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-linear-gradient/-/expo-linear-gradient-8.1.0.tgz#6933765cf1e76ef2928fd8495e779929699ac4c6" - integrity sha512-AIy2pOXQRcgk2XE5IgAzd1S2jTFLutiDfveNm6m3fPAk00Rw4qFe98qzte1ayNrGYLJvQ2xq/Y7C0BmBP051mg== - -expo-location@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-location/-/expo-location-8.1.0.tgz#6a71ad9a8b78d5f016a30a02013c3b28f46d0b1b" - integrity sha512-G9JvsK1t9Z5Iybf+FCG81Jgm9Ee9leqpazxOPVabUJEWu/55Iex3yLGX04BuIA4ozAlJKBPzkhPdyqKdC7zrSw== - dependencies: - invariant "^2.2.4" - expo-modules-autolinking@0.5.5, expo-modules-autolinking@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/expo-modules-autolinking/-/expo-modules-autolinking-0.5.5.tgz#6bcc42072dcbdfca79d207b7f549f1fdb54a2b74" @@ -17119,11 +16042,6 @@ expo-modules-core@0.6.5: compare-versions "^3.4.0" invariant "^2.2.4" -expo-permissions@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-permissions/-/expo-permissions-8.1.0.tgz#a7f2ee91ba76ce3a467e7b10adaa9ca5201b226f" - integrity sha512-QBHD+1J9+sGFnhoEGzMRchPweeEE0OJ9ehG/0l1BMRBA7qsLS9vRC1FTJ55NwjI0Kr4RTha9r6ZX1kZHT09f/w== - expo-pwa@0.0.112: version "0.0.112" resolved "https://registry.yarnpkg.com/expo-pwa/-/expo-pwa-0.0.112.tgz#4eb26a5bf1e5c8d48c371ad8543d44fe41ddfb06" @@ -17135,75 +16053,11 @@ expo-pwa@0.0.112: commander "2.20.0" update-check "1.5.3" -expo-sqlite@~8.1.0: - version "8.1.0" - resolved "https://registry.yarnpkg.com/expo-sqlite/-/expo-sqlite-8.1.0.tgz#858eb28e1143db281de8a49c99b4a953a81d0834" - integrity sha512-ziw6dbV1/sZErDkoGjG0afokyuKQqDtUuJglbLz9rQ6zNS1ceF3AjuEyfsWPDc2LL+QEdcnQODW7VUJelIk+0Q== - dependencies: - "@expo/websql" "^1.0.1" - "@types/websql" "^0.0.27" - lodash "^4.17.15" - expo-status-bar@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/expo-status-bar/-/expo-status-bar-1.2.0.tgz#16e73205da563f9536f562e439081e30e318a82e" integrity sha512-pVZZ/kDCXFK79E4dCtRecs3XLC8aiwlciutSd/fFmUPJSQZ1Txia6hlKajPt0GAYft8/YnT0V3URXzWZOBniYQ== -expo-web-browser@~8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/expo-web-browser/-/expo-web-browser-8.1.1.tgz#93a3d4af834e7bbd1afd54f0cc588016d592c5ae" - integrity sha512-htiXVLo0mb0t8F2vFL3+QnmD97B9U0Ek9cp2BBKSCLeHaVry6RUMewT9HLLcBOJhz2Zdjwk7JmTJh6amF1h80Q== - -expo@37.0.3: - version "37.0.3" - resolved "https://registry.yarnpkg.com/expo/-/expo-37.0.3.tgz#c7dc8d2808264b74882bb2f7bc11c0ce1ce520bc" - integrity sha512-EDQiYItWKEHwmKQHew1KGbD+vpkzaSSS6S/n3YdFywv27O5mLs26Y593UtvdRu/10oot7g0DdFvcCUg7+b//ng== - dependencies: - "@babel/runtime" "^7.1.2" - "@expo/vector-icons" "^10.0.2" - "@types/fbemitter" "^2.0.32" - "@types/invariant" "^2.2.29" - "@types/lodash.zipobject" "^4.1.4" - "@types/qs" "^6.5.1" - "@unimodules/core" "~5.1.0" - "@unimodules/react-native-adapter" "~5.1.1" - babel-preset-expo "~8.1.0" - badgin "^1.1.2" - cross-spawn "^6.0.5" - expo-asset "~8.1.3" - expo-constants "~9.0.0" - expo-error-recovery "~1.1.0" - expo-file-system "~8.1.0" - expo-font "~8.1.0" - expo-keep-awake "~8.1.0" - expo-linear-gradient "~8.1.0" - expo-location "~8.1.0" - expo-permissions "~8.1.0" - expo-sqlite "~8.1.0" - expo-web-browser "~8.1.0" - fbemitter "^2.1.1" - invariant "^2.2.2" - lodash "^4.6.0" - md5-file "^3.2.3" - nullthrows "^1.1.0" - pretty-format "^23.6.0" - prop-types "^15.6.0" - qs "^6.5.0" - react-native-view-shot "3.1.2" - serialize-error "^2.1.0" - unimodules-app-loader "~1.0.0" - unimodules-barcode-scanner-interface "~5.1.0" - unimodules-camera-interface "~5.1.0" - unimodules-constants-interface "~5.1.0" - unimodules-face-detector-interface "~5.1.0" - unimodules-file-system-interface "~5.1.0" - unimodules-font-interface "~5.1.0" - unimodules-image-loader-interface "~5.1.0" - unimodules-permissions-interface "~5.1.0" - unimodules-sensors-interface "~5.1.0" - unimodules-task-manager-interface "~5.1.0" - uuid "^3.4.0" - expo@~44.0.0: version "44.0.6" resolved "https://registry.yarnpkg.com/expo/-/expo-44.0.6.tgz#5454f08abb07166e55eb55b5fc4d45b5ad416ff4" @@ -17339,13 +16193,6 @@ express@^4.14.0, express@^4.16.3, express@^4.16.4, express@^4.17.0, express@^4.1 utils-merge "1.0.1" vary "~1.1.2" -extend-shallow@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-1.1.4.tgz#19d6bf94dfc09d76ba711f39b872d21ff4dd9071" - integrity sha1-Gda/lN/AnXa6cR85uHLSH/TdkHE= - dependencies: - kind-of "^1.1.0" - extend-shallow@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" @@ -17366,15 +16213,6 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^2.0.1, external-editor@^2.0.4: - version "2.2.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5" - integrity sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A== - dependencies: - chardet "^0.4.0" - iconv-lite "^0.4.17" - tmp "^0.0.33" - external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -17433,16 +16271,6 @@ fake-tag@^1.0.0: resolved "https://registry.yarnpkg.com/fake-tag/-/fake-tag-1.0.1.tgz#1d59da482240a02bd83500ca98976530ed154b0d" integrity sha512-qmewZoBpa71mM+y6oxXYW/d1xOYQmeIvnEXAt1oCmdP0sqcogWYLepR87QL1jQVLSVMVYDq2cjY6ec/Wu8/4pg== -fancy-log@^1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.3.tgz#dbc19154f558690150a23953a0adbd035be45fc7" - integrity sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw== - dependencies: - ansi-gray "^0.1.1" - color-support "^1.1.3" - parse-node-version "^1.0.0" - time-stamp "^1.0.0" - fast-deep-equal@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" @@ -17579,56 +16407,26 @@ fbjs-css-vars@^1.0.0: resolved "https://registry.yarnpkg.com/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz#216551136ae02fe255932c3ec8775f18e2c078b8" integrity sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ== -fbjs-scripts@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fbjs-scripts/-/fbjs-scripts-1.2.0.tgz#069a0c0634242d10031c6460ef1fccefcdae8b27" - integrity sha512-5krZ8T0Bf8uky0abPoCLrfa7Orxd8UH4Qq8hRUF2RZYNMu+FmEOrBc7Ib3YVONmxTXTlLAvyrrdrVmksDb2OqQ== - dependencies: - "@babel/core" "^7.0.0" - ansi-colors "^1.0.1" - babel-preset-fbjs "^3.2.0" - core-js "^2.4.1" - cross-spawn "^5.1.0" - fancy-log "^1.3.2" - object-assign "^4.0.1" - plugin-error "^0.1.2" - semver "^5.1.0" - through2 "^2.0.0" - -fbjs@*, fbjs@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" - integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== +fbjs@^0.8.4: + version "0.8.18" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a" + integrity sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA== dependencies: - cross-fetch "^3.1.5" - fbjs-css-vars "^1.0.0" + core-js "^1.0.0" + isomorphic-fetch "^2.1.1" loose-envify "^1.0.0" object-assign "^4.1.0" promise "^7.1.1" setimmediate "^1.0.5" ua-parser-js "^0.7.30" -fbjs@1.0.0, fbjs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-1.0.0.tgz#52c215e0883a3c86af2a7a776ed51525ae8e0a5a" - integrity sha512-MUgcMEJaFhCaF1QtWGnmq9ZDRAzECTCRAF7O6UZIlAlkTs1SasiX9aP0Iw7wfD2mJ7wDTNfg2w7u5fSCwJk1OA== +fbjs@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-3.0.4.tgz#e1871c6bd3083bac71ff2da868ad5067d37716c6" + integrity sha512-ucV0tDODnGV3JCnnkmoszb5lf4bNpzjv80K41wd4k798Etq+UYD0y0TIfalLjZoKgjive6/adkRnszwapiDgBQ== dependencies: - core-js "^2.4.1" + cross-fetch "^3.1.5" fbjs-css-vars "^1.0.0" - isomorphic-fetch "^2.1.1" - loose-envify "^1.0.0" - object-assign "^4.1.0" - promise "^7.1.1" - setimmediate "^1.0.5" - ua-parser-js "^0.7.18" - -fbjs@^0.8.15, fbjs@^0.8.4: - version "0.8.18" - resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a" - integrity sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA== - dependencies: - core-js "^1.0.0" - isomorphic-fetch "^2.1.1" loose-envify "^1.0.0" object-assign "^4.1.0" promise "^7.1.1" @@ -17788,11 +16586,6 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -filter-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b" - integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs= - finalhandler@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105" @@ -17940,7 +16733,7 @@ find-yarn-workspace-root@~2.0.0: dependencies: micromatch "^4.0.2" -findup-sync@3.0.0, findup-sync@^3.0.0: +findup-sync@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1" integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg== @@ -18039,36 +16832,16 @@ fontfaceobserver@^2.1.0: resolved "https://registry.yarnpkg.com/fontfaceobserver/-/fontfaceobserver-2.1.0.tgz#e2705d293e2c585a6531c2a722905657317a2991" integrity sha512-ReOsO2F66jUa0jmv2nlM/s1MiutJx/srhAe2+TE8dJCMi02ZZOcCTxTCQFr3Yet+uODUtnr4Mewg+tNQ+4V1Ng== -for-in@^0.1.3: - version "0.1.8" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" - integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= - -for-in@^1.0.1, for-in@^1.0.2: +for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= -for-own@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" - integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= - dependencies: - for-in "^1.0.1" - foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= -foreground-child@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" - integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== - dependencies: - cross-spawn "^7.0.0" - signal-exit "^3.0.2" - forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -19051,11 +17824,6 @@ gray-matter@^4.0.3: section-matter "^1.0.0" strip-bom-string "^1.0.0" -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== - gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -19089,11 +17857,6 @@ hable@^3.0.0: resolved "https://registry.yarnpkg.com/hable/-/hable-3.0.0.tgz#6de089b2df946635cf8134b9e4859f1b62de255f" integrity sha512-7+G0/2/COR8pwteYFqHIVYfQpuEiO2HXwJrhCBJVgrNrl9O5eaUoJVDGXUJX+0RpGncNVTuestexjk1afj01wQ== -hammerjs@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1" - integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE= - handle-thing@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" @@ -19305,13 +18068,6 @@ hashids@1.1.4: resolved "https://registry.yarnpkg.com/hashids/-/hashids-1.1.4.tgz#e4ff92ad66b684a3bd6aace7c17d66618ee5fa21" integrity sha512-U/fnTE3edW0AV92ZI/BfEluMZuVcu3MDOopsN7jS+HqDYcarQo8rXQiWlsBlm0uX48/taYSdxRsfzh2HRg5Z6w== -"hashish@>=0.0.2 <0.1": - version "0.0.4" - resolved "https://registry.yarnpkg.com/hashish/-/hashish-0.0.4.tgz#6d60bc6ffaf711b6afd60e426d077988014e6554" - integrity sha1-bWC8b/r3Ebav1g5CbQd5iAFOZVQ= - dependencies: - traverse ">=0.2.4" - hast-to-hyperscript@^10.0.0: version "10.0.1" resolved "https://registry.yarnpkg.com/hast-to-hyperscript/-/hast-to-hyperscript-10.0.1.tgz#3decd7cb4654bca8883f6fcbd4fb3695628c4296" @@ -19451,11 +18207,6 @@ header-case@^2.0.3: capital-case "^1.0.4" tslib "^2.0.3" -hermes-engine@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.2.1.tgz#25c0f1ff852512a92cb5c5cc47cf967e1e722ea2" - integrity sha512-eNHUQHuadDMJARpaqvlCZoK/Nitpj6oywq3vQ3wCwEsww5morX34mW5PmKWQTO7aU0ck0hgulxR+EVDlXygGxQ== - hermes-engine@~0.7.0: version "0.7.2" resolved "https://registry.yarnpkg.com/hermes-engine/-/hermes-engine-0.7.2.tgz#303cd99d23f68e708b223aec2d49d5872985388b" @@ -19488,28 +18239,6 @@ highlight.js@~9.13.0: resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== -history@4.10.1, history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - -history@^3.0.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/history/-/history-3.3.0.tgz#fcedcce8f12975371545d735461033579a6dae9c" - integrity sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw= - dependencies: - invariant "^2.2.1" - loose-envify "^1.2.0" - query-string "^4.2.2" - warning "^3.0.0" - hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -19527,12 +18256,7 @@ hogan.js@^3.0.2: mkdirp "0.3.0" nopt "1.0.10" -hoist-non-react-statics@^2.3.1: - version "2.5.5" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47" - integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw== - -hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== @@ -20016,7 +18740,7 @@ iconv-lite@0.4.23: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.4.24, iconv-lite@^0.4.17, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -20105,7 +18829,7 @@ image-size@^1.0.0: dependencies: queue "6.0.2" -immediate@^3.2.2, immediate@^3.2.3: +immediate@^3.2.3: version "3.3.0" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== @@ -20120,21 +18844,11 @@ immer@8.0.1: resolved "https://registry.yarnpkg.com/immer/-/immer-8.0.1.tgz#9c73db683e2b3975c424fb0572af5889877ae656" integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA== -immutable@^3.7.4: - version "3.8.2" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.8.2.tgz#c2439951455bb39913daf281376f1530e104adf3" - integrity sha1-wkOZUUVbs5kT2vKBN28VMOEErfM= - immutable@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.1.0.tgz#f795787f0db780183307b9eb2091fcac1f6fafef" integrity sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ== -immutable@~3.7.4: - version "3.7.6" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-3.7.6.tgz#13b4d3cb12befa15482a26fe1b2ebae640071e4b" - integrity sha1-E7TTyxK++hVIKib+Gy665kAHHks= - import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -20286,13 +19000,6 @@ inline-style-parser@0.1.1: resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== -inline-style-prefixer@^5.0.3: - version "5.1.2" - resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-5.1.2.tgz#e5a5a3515e25600e016b71e39138971228486c33" - integrity sha512-PYUF+94gDfhy+LsQxM0g3d6Hge4l1pAqOSOiZuHWzMvQEGsbRQ/ck2WioLqrY2ZkHyPgVUXxn+hrkF7D6QUGbA== - dependencies: - css-in-js-utils "^2.0.0" - inline-style-prefixer@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz#c5c0e43ba8831707afc5f5bbfd97edf45c1fa7ae" @@ -20307,25 +19014,6 @@ inputformat-to-jstransformer@^1.2.1: dependencies: require-one "^1.0.3" -inquirer@3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347" - integrity sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c= - dependencies: - ansi-escapes "^1.1.0" - chalk "^1.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.1" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx "^4.1.0" - string-width "^2.0.0" - strip-ansi "^3.0.0" - through "^2.3.6" - inquirer@6.5.0: version "6.5.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42" @@ -20383,26 +19071,6 @@ inquirer@8.0.0: strip-ansi "^6.0.0" through "^2.3.6" -inquirer@^3.0.6: - version "3.3.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" - integrity sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ== - dependencies: - ansi-escapes "^3.0.0" - chalk "^2.0.0" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^2.0.4" - figures "^2.0.0" - lodash "^4.3.0" - mute-stream "0.0.7" - run-async "^2.2.0" - rx-lite "^4.0.8" - rx-lite-aggregates "^4.0.8" - string-width "^2.1.0" - strip-ansi "^4.0.0" - through "^2.3.6" - inquirer@^7.0.0, inquirer@^7.3.3: version "7.3.3" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" @@ -20491,7 +19159,7 @@ interpret@1.2.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== -interpret@^1.0.0, interpret@^1.4.0: +interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== @@ -20501,7 +19169,7 @@ interpret@^2.0.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.0.0.tgz#b783ffac0b8371503e9ab39561df223286aa5433" integrity sha512-e0/LknJ8wpMMhTiWcjivB+ESwIuvHnBSlBbmP/pSb8CQJldoj1p2qv7xGZ/+BtbTziYRFSz8OsvdbiX45LtYQA== -invariant@*, invariant@2.2.4, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: +invariant@2.2.4, invariant@^2.2.2, invariant@^2.2.3, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -20635,7 +19303,7 @@ is-boolean-object@^1.0.1, is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.0.2, is-buffer@^1.1.0, is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.1: +is-buffer@^1.1.0, is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.1: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -21278,7 +19946,7 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: +istanbul-lib-coverage@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== @@ -21288,7 +19956,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: +istanbul-lib-instrument@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== @@ -21312,15 +19980,6 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" -istanbul-lib-report@^2.0.4: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== - dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" - istanbul-lib-report@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" @@ -21330,17 +19989,6 @@ istanbul-lib-report@^3.0.0: make-dir "^3.0.0" supports-color "^7.1.0" -istanbul-lib-source-maps@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== - dependencies: - debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" - source-map "^0.6.1" - istanbul-lib-source-maps@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" @@ -21350,14 +19998,7 @@ istanbul-lib-source-maps@^4.0.0: istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== - dependencies: - html-escaper "^2.0.0" - -istanbul-reports@^3.1.3, istanbul-reports@^3.1.4: +istanbul-reports@^3.1.3: version "3.1.5" resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.5.tgz#cc9a6ab25cb25659810e4785ed9d9fb742578bae" integrity sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w== @@ -21421,15 +20062,6 @@ javascript-stringify@^1.6.0: resolved "https://registry.yarnpkg.com/javascript-stringify/-/javascript-stringify-1.6.0.tgz#142d111f3a6e3dae8f4a9afd77d45855b5a9cce3" integrity sha512-fnjC0up+0SjEJtgmmG+teeel68kutkvzfctO/KxE3qJlbunkJYAshgH3boU++gSBHP8z5/r0ts0qRIrHf0RTQQ== -jest-changed-files@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== - dependencies: - "@jest/types" "^24.9.0" - execa "^1.0.0" - throat "^4.0.0" - jest-changed-files@^27.4.2: version "27.4.2" resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.4.2.tgz#da2547ea47c6e6a5f6ed336151bd2075736eb4a5" @@ -21464,25 +20096,6 @@ jest-circus@^27.4.6: stack-utils "^2.0.3" throat "^6.0.1" -jest-cli@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" - integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== - dependencies: - "@jest/core" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - exit "^0.1.2" - import-local "^2.0.0" - is-ci "^2.0.0" - jest-config "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^13.3.0" - jest-cli@^27.4.7: version "27.4.7" resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.4.7.tgz#d00e759e55d77b3bcfea0715f527c394ca314e5a" @@ -21501,29 +20114,6 @@ jest-cli@^27.4.7: prompts "^2.0.1" yargs "^16.2.0" -jest-config@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" - integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.9.0" - "@jest/types" "^24.9.0" - babel-jest "^24.9.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.9.0" - jest-environment-node "^24.9.0" - jest-get-type "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - micromatch "^3.1.10" - pretty-format "^24.9.0" - realpath-native "^1.1.0" - jest-config@^27.4.7: version "27.4.7" resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.4.7.tgz#4f084b2acbd172c8b43aa4cdffe75d89378d3972" @@ -21562,23 +20152,6 @@ jest-diff@*, jest-diff@27.4.6, jest-diff@^27.0.0, jest-diff@^27.4.6: jest-get-type "^27.4.0" pretty-format "^27.4.6" -jest-diff@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-docblock@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" - integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== - dependencies: - detect-newline "^2.1.0" - jest-docblock@^27.4.0: version "27.4.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.4.0.tgz#06c78035ca93cbbb84faf8fce64deae79a59f69f" @@ -21586,17 +20159,6 @@ jest-docblock@^27.4.0: dependencies: detect-newline "^3.0.0" -jest-each@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" - integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== - dependencies: - "@jest/types" "^24.9.0" - chalk "^2.0.1" - jest-get-type "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - jest-each@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.4.6.tgz#e7e8561be61d8cc6dbf04296688747ab186c40ff" @@ -21626,18 +20188,6 @@ jest-environment-jsdom@27.1.0: jest-util "^27.1.0" jsdom "^16.6.0" -jest-environment-jsdom@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" - integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jsdom "^11.5.1" - jest-environment-jsdom@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz#c23a394eb445b33621dfae9c09e4c8021dea7b36" @@ -21651,17 +20201,6 @@ jest-environment-jsdom@^27.4.6: jest-util "^27.4.2" jsdom "^16.6.0" -jest-environment-node@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" - integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jest-environment-node@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.4.6.tgz#ee8cd4ef458a0ef09d087c8cd52ca5856df90242" @@ -21674,25 +20213,6 @@ jest-environment-node@^27.4.6: jest-mock "^27.4.6" jest-util "^27.4.2" -jest-expo@37.0.0: - version "37.0.0" - resolved "https://registry.yarnpkg.com/jest-expo/-/jest-expo-37.0.0.tgz#2d2c5ea4622585ca6539612245f3357bc91d7b70" - integrity sha512-Bww1296svavIqGMgev7taLloi87WtwgEHXVtSmNMaKeKfBaFK05qkEzRM3xE/8cnMrYNJSlqusvA7PApdvE/vg== - dependencies: - "@expo/config" "^2.5.3" - babel-jest "^24.7.1" - jest "^24.7.1" - jest-watch-select-projects "^1.0.0" - jest-watch-typeahead "^0.4.0" - json5 "^2.1.0" - lodash "^4.5.0" - react-test-renderer "~16.9.0" - -jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -21703,7 +20223,7 @@ jest-get-type@^27.4.0: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.4.0.tgz#7503d2663fffa431638337b3998d39c5e928e9b5" integrity sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ== -jest-haste-map@^24.7.1, jest-haste-map@^24.9.0: +jest-haste-map@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== @@ -21777,28 +20297,6 @@ jest-image-snapshot@2.12.0: pngjs "^3.3.3" rimraf "^2.6.2" -jest-jasmine2@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" - integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - co "^4.6.0" - expect "^24.9.0" - is-generator-fn "^2.0.0" - jest-each "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - throat "^4.0.0" - jest-jasmine2@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz#109e8bc036cb455950ae28a018f983f2abe50127" @@ -21832,14 +20330,6 @@ jest-junit@12.2.0: uuid "^8.3.2" xml "^1.0.1" -jest-leak-detector@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" - integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== - dependencies: - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-leak-detector@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz#ed9bc3ce514b4c582637088d9faf58a33bd59bf4" @@ -21848,16 +20338,6 @@ jest-leak-detector@^27.4.6: jest-get-type "^27.4.0" pretty-format "^27.4.6" -jest-matcher-utils@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" - integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - jest-matcher-utils@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz#53ca7f7b58170638590e946f5363b988775509b8" @@ -21882,20 +20362,6 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" -jest-message-util@^25.1.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea" - integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^25.5.0" - "@types/stack-utils" "^1.0.1" - chalk "^3.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - slash "^3.0.0" - stack-utils "^1.0.1" - jest-message-util@^27.4.6: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" @@ -21926,12 +20392,12 @@ jest-mock@^27.1.0, jest-mock@^27.4.6: "@jest/types" "^27.4.2" "@types/node" "*" -jest-pnp-resolver@^1.2.1, jest-pnp-resolver@^1.2.2: +jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: +jest-regex-util@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== @@ -21946,15 +20412,6 @@ jest-regex-util@^27.0.0, jest-regex-util@^27.4.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== -jest-resolve-dependencies@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" - integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== - dependencies: - "@jest/types" "^24.9.0" - jest-regex-util "^24.3.0" - jest-snapshot "^24.9.0" - jest-resolve-dependencies@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz#fc50ee56a67d2c2183063f6a500cc4042b5e2327" @@ -21964,17 +20421,6 @@ jest-resolve-dependencies@^27.4.6: jest-regex-util "^27.4.0" jest-snapshot "^27.4.6" -jest-resolve@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" - integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== - dependencies: - "@jest/types" "^24.9.0" - browser-resolve "^1.11.3" - chalk "^2.0.1" - jest-pnp-resolver "^1.2.1" - realpath-native "^1.1.0" - jest-resolve@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.4.6.tgz#2ec3110655e86d5bfcfa992e404e22f96b0b5977" @@ -21991,31 +20437,6 @@ jest-resolve@^27.4.6: resolve.exports "^1.1.0" slash "^3.0.0" -jest-runner@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" - integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-docblock "^24.3.0" - jest-haste-map "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-leak-detector "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - source-map-support "^0.5.6" - throat "^4.0.0" - jest-runner@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.4.6.tgz#1d390d276ec417e9b4d0d081783584cbc3e24773" @@ -22044,35 +20465,6 @@ jest-runner@^27.4.6: source-map-support "^0.5.6" throat "^6.0.1" -jest-runtime@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" - integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - realpath-native "^1.1.0" - slash "^2.0.0" - strip-bom "^3.0.0" - yargs "^13.3.0" - jest-runtime@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.4.6.tgz#83ae923818e3ea04463b22f3597f017bb5a1cffa" @@ -22108,7 +20500,7 @@ jest-serializer-html@7.1.0: dependencies: diffable-html "^4.1.0" -jest-serializer@^24.4.0, jest-serializer@^24.9.0: +jest-serializer@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== @@ -22129,25 +20521,6 @@ jest-serializer@^27.4.0: "@types/node" "*" graceful-fs "^4.2.4" -jest-snapshot@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" - integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - expect "^24.9.0" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - pretty-format "^24.9.0" - semver "^6.2.0" - jest-snapshot@^27.4.6: version "27.4.6" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.4.6.tgz#e2a3b4fff8bdce3033f2373b2e525d8b6871f616" @@ -22218,18 +20591,6 @@ jest-util@^27.0.0, jest-util@^27.1.0, jest-util@^27.4.2: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^24.7.0, jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" - leven "^3.1.0" - pretty-format "^24.9.0" - jest-validate@^26.5.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" @@ -22263,15 +20624,6 @@ jest-vue-preprocessor@1.7.1: find-babel-config "1.2.0" vue-property-decorator "8.3.0" -jest-watch-select-projects@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jest-watch-select-projects/-/jest-watch-select-projects-1.0.0.tgz#c876d787006b42c52f1a7dad2cfca5e929eaa283" - integrity sha512-8zO2NNeTQG5+o9BYi4n6Idp8QZzCQdirpTel5iaed9911ktDKV0VTdiu0tYvDOoAbdfH4itTM4gR6lcJ2ATc/w== - dependencies: - ansi-escapes "^3.1.0" - chalk "^2.4.1" - prompts "^2.2.1" - jest-watch-typeahead@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.3.0.tgz#f56d9ee17ea71ecbf8253fed213df3185a1584c9" @@ -22297,20 +20649,7 @@ jest-watch-typeahead@1.0.0: string-length "^5.0.1" strip-ansi "^7.0.1" -jest-watch-typeahead@^0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/jest-watch-typeahead/-/jest-watch-typeahead-0.4.2.tgz#e5be959698a7fa2302229a5082c488c3c8780a4a" - integrity sha512-f7VpLebTdaXs81rg/oj4Vg/ObZy2QtGzAmGLNsqUS5G5KtSN68tFcIsbvNODfNyQxU78g7D8x77o3bgfBTR+2Q== - dependencies: - ansi-escapes "^4.2.1" - chalk "^2.4.1" - jest-regex-util "^24.9.0" - jest-watcher "^24.3.0" - slash "^3.0.0" - string-length "^3.1.0" - strip-ansi "^5.0.0" - -jest-watcher@^24.3.0, jest-watcher@^24.9.0: +jest-watcher@^24.3.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== @@ -22336,7 +20675,7 @@ jest-watcher@^27.0.0, jest-watcher@^27.4.6: jest-util "^27.4.2" string-length "^4.0.1" -jest-worker@^24.0.0, jest-worker@^24.6.0, jest-worker@^24.9.0: +jest-worker@^24.0.0, jest-worker@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== @@ -22371,14 +20710,6 @@ jest@27.4.7: import-local "^3.0.2" jest-cli "^27.4.7" -jest@^24.7.1: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" - integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== - dependencies: - import-local "^2.0.0" - jest-cli "^24.9.0" - jetifier@^1.6.2: version "1.6.8" resolved "https://registry.yarnpkg.com/jetifier/-/jetifier-1.6.8.tgz#e88068697875cbda98c32472902c4d3756247798" @@ -22773,13 +21104,6 @@ json-stable-stringify-without-jsonify@^1.0.1: resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= -json-stable-stringify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" - integrity sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8= - dependencies: - jsonify "~0.0.0" - json-stable-stringify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" @@ -22797,19 +21121,12 @@ json-stringify-safe@5.0.x, json-stringify-safe@^5.0.1, json-stringify-safe@~5.0. resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json2mq@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/json2mq/-/json2mq-0.2.0.tgz#b637bd3ba9eabe122c83e9720483aeb10d2c904a" - integrity sha1-tje9O6nqvhIsg+lyBIOusQ0skEo= - dependencies: - string-convert "^0.2.0" - json3@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA== -json5@2.x, json5@^2.1.0, json5@^2.1.1, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0, json5@^2.2.1: +json5@2.x, json5@^2.1.1, json5@^2.1.2, json5@^2.1.3, json5@^2.2.0, json5@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.2.tgz#64471c5bdcc564c18f7c1d4df2e2297f2457c5ab" integrity sha512-46Tk9JiOL2z7ytNQWFLpj99RZkVgeHf87yGQKsIkaPz1qSH9UczKH1rO7K3wgRselo0tYMUNfecYpm/p1vC7tQ== @@ -22961,18 +21278,6 @@ killable@^1.0.1: resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892" integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg== -kind-of@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-1.1.0.tgz#140a3d2d41a36d2efcfa9377b62c24f8495a5c44" - integrity sha1-FAo9LUGjbS78+pN3tiwk+ElaXEQ= - -kind-of@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" - integrity sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU= - dependencies: - is-buffer "^1.0.2" - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -23095,11 +21400,6 @@ lazy-ass@1.6.0: resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== -lazy-cache@^0.2.3: - version "0.2.7" - resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" - integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U= - lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" @@ -23371,16 +21671,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -load-json-file@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" - integrity sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - strip-bom "^3.0.0" - load-json-file@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" @@ -23524,7 +21814,7 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= -lodash.debounce@^4.0.0, lodash.debounce@^4.0.8: +lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= @@ -23624,11 +21914,6 @@ lodash.omit@^4.0.2, lodash.omit@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= -lodash.orderby@4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.orderby/-/lodash.orderby-4.6.0.tgz#e697f04ce5d78522f54d9338b32b81a3393e4eb3" - integrity sha1-5pfwTOXXhSL1TZM4syuBozk+TrM= - lodash.padend@^4.6.1: version "4.6.1" resolved "https://registry.yarnpkg.com/lodash.padend/-/lodash.padend-4.6.1.tgz#53ccba047d06e158d311f45da625f4e49e6f166e" @@ -23664,7 +21949,7 @@ lodash.templatesettings@^4.0.0: dependencies: lodash._reinterpolate "~3.0.0" -lodash.throttle@^4.0.0, lodash.throttle@^4.1.1: +lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ= @@ -23694,7 +21979,7 @@ lodash.zip@^4.2.0: resolved "https://registry.yarnpkg.com/lodash.zip/-/lodash.zip-4.2.0.tgz#ec6662e4896408ed4ab6c542a3990b72cc080020" integrity sha1-7GZi5IlkCO1KtsVCo5kLcswIACA= -"lodash@>=3.5 <5", lodash@^4.0.0, lodash@^4.0.1, lodash@^4.15.0, lodash@^4.16.5, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.0, lodash@^4.7.0, lodash@~4.17.10, lodash@~4.17.15: +"lodash@>=3.5 <5", lodash@^4.0.1, lodash@^4.15.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.7.0, lodash@~4.17.10, lodash@~4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -23740,15 +22025,6 @@ log-update@^3.2.0: cli-cursor "^2.1.0" wrap-ansi "^5.0.0" -logkitty@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.6.1.tgz#fe29209669d261539cbd6bb998a136fc92a1a05c" - integrity sha512-cHuXN8qUZuzX/7kB6VyS7kB4xyD24e8gyHXIFNhIv+fjW3P+jEXNUhj0o/7qWJtv7UZpbnPgUqzu/AZQ8RAqxQ== - dependencies: - ansi-fragments "^0.2.1" - dayjs "^1.8.15" - yargs "^12.0.5" - logkitty@^0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/logkitty/-/logkitty-0.7.1.tgz#8e8d62f4085a826e8d38987722570234e33c6aa7" @@ -23778,7 +22054,7 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha512-k+yt5n3l48JU4k8ftnKG6V7u32wyH2NfKzeMto9F/QRE0amxy/LayxwlvjjkZEIzqR+19IrtFO8p5kB9QaYUFg== -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -24274,13 +22550,6 @@ media-typer@0.3.0: resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= -mem@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/mem/-/mem-1.1.0.tgz#5edd52b485ca1d900fe64895505399a0dfa45f76" - integrity sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y= - dependencies: - mimic-fn "^1.0.0" - mem@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/mem/-/mem-4.0.0.tgz#6437690d9471678f6cc83659c00cbafcd6b0cdaf" @@ -24389,15 +22658,6 @@ meow@^9.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" -merge-deep@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.3.tgz#1a2b2ae926da8b2ae93a0ac15d90cd1922766003" - integrity sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA== - dependencies: - arr-union "^3.1.0" - clone-deep "^0.2.4" - kind-of "^3.0.2" - merge-descriptors@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" @@ -24410,13 +22670,6 @@ merge-source-map@^1.1.0: dependencies: source-map "^0.6.1" -merge-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" - integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= - dependencies: - readable-stream "^2.0.1" - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -24511,24 +22764,6 @@ metro-babel-register@0.64.0: "@babel/register" "^7.0.0" escape-string-regexp "^1.0.5" -metro-babel-register@^0.56.0, metro-babel-register@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-babel-register/-/metro-babel-register-0.56.4.tgz#b0c627a1cfdd1bdd768f81af79481754e833a902" - integrity sha512-Phm6hMluOWYqfykftjJ1jsTpWvbgb49AC/1taxEctxUdRCZlFgZwBleJZAhQYxJD5J+ikFkEbHDzePEXb29KVA== - dependencies: - "@babel/core" "^7.0.0" - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-transform-async-to-generator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/register" "^7.0.0" - core-js "^2.2.2" - escape-string-regexp "^1.0.5" - metro-babel-transformer@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.64.0.tgz#a21f8a989a5ea60c1109456e21bd4d9374194ea0" @@ -24538,14 +22773,6 @@ metro-babel-transformer@0.64.0: metro-source-map "0.64.0" nullthrows "^1.1.1" -metro-babel-transformer@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-babel-transformer/-/metro-babel-transformer-0.56.4.tgz#fe1d0dc600fcf90201a5bea4d42caea10b801057" - integrity sha512-IOi4ILgZvaX7GCGHBJp79paNVOq5QxhhbyqAdEJgDP8bHfl/OVHoVKSypfrsMSKSiBrqxhIjyc4XjkXsQtkx5g== - dependencies: - "@babel/core" "^7.0.0" - metro-source-map "^0.56.4" - metro-cache-key@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-cache-key/-/metro-cache-key-0.64.0.tgz#98d0a94332453c4c52b74f72c07cc62a5c264c4f" @@ -24560,16 +22787,6 @@ metro-cache@0.64.0: mkdirp "^0.5.1" rimraf "^2.5.4" -metro-cache@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-cache/-/metro-cache-0.56.4.tgz#542f9f8a35f8fb9d5576f46fd3ab4d4f42851a7e" - integrity sha512-d1hiUSKwtRsuMxUhHVJ3tjK2BbpUlJGvTyMWohK8Wxx+0GbnWRWWFcI4vlCzlZfoK0VtZK2MJEl5t7Du1mIniQ== - dependencies: - jest-serializer "^24.4.0" - metro-core "^0.56.4" - mkdirp "^0.5.1" - rimraf "^2.5.4" - metro-config@0.64.0, metro-config@^0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.64.0.tgz#b634fa05cffd06b1e50e4339c200f90a42924afb" @@ -24582,18 +22799,6 @@ metro-config@0.64.0, metro-config@^0.64.0: metro-core "0.64.0" metro-runtime "0.64.0" -metro-config@^0.56.0, metro-config@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-config/-/metro-config-0.56.4.tgz#338fd8165fba59424cec427c1a881757945e57e9" - integrity sha512-O85QDHwWdMn/8ERe13y4a6vbZL0AHyO8atTvL+9BCulLEO+FQBi1iJjr3+ViLa8cf0m5dRftDsa7P47m5euk4A== - dependencies: - cosmiconfig "^5.0.5" - jest-validate "^24.7.0" - metro "^0.56.4" - metro-cache "^0.56.4" - metro-core "^0.56.4" - pretty-format "^24.7.0" - metro-core@0.64.0, metro-core@^0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.64.0.tgz#7616b27acfe7baa476f6cd6bd9e70ae64fa62541" @@ -24603,16 +22808,6 @@ metro-core@0.64.0, metro-core@^0.64.0: lodash.throttle "^4.1.1" metro-resolver "0.64.0" -metro-core@^0.56.0, metro-core@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-core/-/metro-core-0.56.4.tgz#67cc41b3c0bf66e9c2306f50239a1080b1e82312" - integrity sha512-hMzkBdgPt5Zm9nr/1KtIT+A6H7TNiLVCEGG5OiAXj8gTRsA2yy7wAdQpwy0xbE+zi88t/pLOzXpd3ClG/YxyWg== - dependencies: - jest-haste-map "^24.7.1" - lodash.throttle "^4.1.1" - metro-resolver "^0.56.4" - wordwrap "^1.0.0" - metro-hermes-compiler@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-hermes-compiler/-/metro-hermes-compiler-0.64.0.tgz#e6043d7aa924e5b2be99bd3f602e693685d15386" @@ -24628,17 +22823,6 @@ metro-inspector-proxy@0.64.0: ws "^1.1.5" yargs "^15.3.1" -metro-inspector-proxy@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-inspector-proxy/-/metro-inspector-proxy-0.56.4.tgz#7343ff3c5908af4fd99e96b6d646e24e99816be4" - integrity sha512-E1S3MO25mWKmcLn1UQuCDiS0hf9P2Fwq8sEAX5lBLoZbehepNH+4xJ3xXSY51JX4dozBrE8GGoKL4ll3II40LA== - dependencies: - connect "^3.6.5" - debug "^2.2.0" - rxjs "^5.4.3" - ws "^1.1.5" - yargs "^9.0.0" - metro-minify-uglify@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.64.0.tgz#da6ab4dda030e3211f5924e7f41ed308d466068f" @@ -24646,13 +22830,6 @@ metro-minify-uglify@0.64.0: dependencies: uglify-es "^3.1.9" -metro-minify-uglify@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-minify-uglify/-/metro-minify-uglify-0.56.4.tgz#13589dfb1d43343608aacb7f78ddfcc052daa63c" - integrity sha512-BHgj7+BKEK2pHvWHUR730bIrsZwl8DPtr49x9L0j2grPZ5/UROWXzEr8VZgIss7fl64t845uu1HXNNyuSj2EhA== - dependencies: - uglify-es "^3.1.9" - metro-react-native-babel-preset@0.64.0, metro-react-native-babel-preset@~0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.64.0.tgz#76861408681dfda3c1d962eb31a8994918c976f8" @@ -24698,47 +22875,6 @@ metro-react-native-babel-preset@0.64.0, metro-react-native-babel-preset@~0.64.0: "@babel/template" "^7.0.0" react-refresh "^0.4.0" -metro-react-native-babel-preset@^0.56.0, metro-react-native-babel-preset@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.56.4.tgz#dcedc64b7ff5c0734839458e70eb0ebef6d063a8" - integrity sha512-CzbBDM9Rh6w8s1fq+ZqihAh7DDqUAcfo9pPww25+N/eJ7UK436Q7JdfxwdIPpBwLFn6o6MyYn+uwL9OEWBJarA== - dependencies: - "@babel/plugin-proposal-class-properties" "^7.0.0" - "@babel/plugin-proposal-export-default-from" "^7.0.0" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.0.0" - "@babel/plugin-proposal-object-rest-spread" "^7.0.0" - "@babel/plugin-proposal-optional-catch-binding" "^7.0.0" - "@babel/plugin-proposal-optional-chaining" "^7.0.0" - "@babel/plugin-syntax-dynamic-import" "^7.0.0" - "@babel/plugin-syntax-export-default-from" "^7.0.0" - "@babel/plugin-syntax-flow" "^7.2.0" - "@babel/plugin-transform-arrow-functions" "^7.0.0" - "@babel/plugin-transform-block-scoping" "^7.0.0" - "@babel/plugin-transform-classes" "^7.0.0" - "@babel/plugin-transform-computed-properties" "^7.0.0" - "@babel/plugin-transform-destructuring" "^7.0.0" - "@babel/plugin-transform-exponentiation-operator" "^7.0.0" - "@babel/plugin-transform-flow-strip-types" "^7.0.0" - "@babel/plugin-transform-for-of" "^7.0.0" - "@babel/plugin-transform-function-name" "^7.0.0" - "@babel/plugin-transform-literals" "^7.0.0" - "@babel/plugin-transform-modules-commonjs" "^7.0.0" - "@babel/plugin-transform-object-assign" "^7.0.0" - "@babel/plugin-transform-parameters" "^7.0.0" - "@babel/plugin-transform-react-display-name" "^7.0.0" - "@babel/plugin-transform-react-jsx" "^7.0.0" - "@babel/plugin-transform-react-jsx-source" "^7.0.0" - "@babel/plugin-transform-regenerator" "^7.0.0" - "@babel/plugin-transform-runtime" "^7.0.0" - "@babel/plugin-transform-shorthand-properties" "^7.0.0" - "@babel/plugin-transform-spread" "^7.0.0" - "@babel/plugin-transform-sticky-regex" "^7.0.0" - "@babel/plugin-transform-template-literals" "^7.0.0" - "@babel/plugin-transform-typescript" "^7.0.0" - "@babel/plugin-transform-unicode-regex" "^7.0.0" - "@babel/template" "^7.0.0" - react-refresh "^0.4.0" - metro-react-native-babel-transformer@0.64.0, metro-react-native-babel-transformer@^0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.64.0.tgz#eafef756972f20efdc51bd5361d55f8598355623" @@ -24751,17 +22887,6 @@ metro-react-native-babel-transformer@0.64.0, metro-react-native-babel-transforme metro-source-map "0.64.0" nullthrows "^1.1.1" -metro-react-native-babel-transformer@^0.56.0: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.56.4.tgz#3c6e48b605c305362ee624e45ff338656e35fc1d" - integrity sha512-ng74eutuy1nyGI9+TDzzVAVfEmNPDlapV4msTQMKPi4EFqo/fBn7Ct33ME9l5E51pQBBnxt/UwcpTvd13b29kQ== - dependencies: - "@babel/core" "^7.0.0" - babel-preset-fbjs "^3.1.2" - metro-babel-transformer "^0.56.4" - metro-react-native-babel-preset "^0.56.4" - metro-source-map "^0.56.4" - metro-resolver@0.64.0, metro-resolver@^0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.64.0.tgz#21126b44f31346ac2ce0b06b77ef65e8c9e2294a" @@ -24769,13 +22894,6 @@ metro-resolver@0.64.0, metro-resolver@^0.64.0: dependencies: absolute-path "^0.0.0" -metro-resolver@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-resolver/-/metro-resolver-0.56.4.tgz#9876f57bca37fd1bfcffd733541e2ee4a89fad7f" - integrity sha512-Ug4ulVfpkKZ1Wu7mdYj9XLGuOqZTuWCqEhyx3siKTc/2eBwKZQXmiNo5d/IxWNvmwL/87Abeb724I6CMzMfjiQ== - dependencies: - absolute-path "^0.0.0" - metro-runtime@0.64.0, metro-runtime@^0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-runtime/-/metro-runtime-0.64.0.tgz#cdaa1121d91041bf6345f2a69eb7c2fb289eff7b" @@ -24795,19 +22913,6 @@ metro-source-map@0.64.0: source-map "^0.5.6" vlq "^1.0.0" -metro-source-map@^0.56.0, metro-source-map@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-source-map/-/metro-source-map-0.56.4.tgz#868ccac3f3519fe14eca358bc186f63651b2b9bc" - integrity sha512-f1P9/rpFmG3Z0Jatiw2zvLItx1TwR7mXTSDj4qLDCWeVMB3kEXAr3R0ucumTW8c6HfpJljeRBWzYFXF33fd81g== - dependencies: - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - invariant "^2.2.4" - metro-symbolicate "^0.56.4" - ob1 "^0.56.4" - source-map "^0.5.6" - vlq "^1.0.0" - metro-symbolicate@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.64.0.tgz#405c21438ab553c29f6841da52ca76ee87bb06ac" @@ -24820,17 +22925,6 @@ metro-symbolicate@0.64.0: through2 "^2.0.1" vlq "^1.0.0" -metro-symbolicate@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro-symbolicate/-/metro-symbolicate-0.56.4.tgz#53e9d40beac9049fa75a3e620ddd47d4907ff015" - integrity sha512-8mCNNn6zV5FFKCIcRgI7736Xl+owgvYuy8qanPxZN36f7utiWRYeB+PirEBPcglBk4qQvoy2lT6oPULNXZQbbQ== - dependencies: - invariant "^2.2.4" - metro-source-map "^0.56.4" - source-map "^0.5.6" - through2 "^2.0.1" - vlq "^1.0.0" - metro-transform-plugins@0.64.0: version "0.64.0" resolved "https://registry.yarnpkg.com/metro-transform-plugins/-/metro-transform-plugins-0.64.0.tgz#41d3dce0f2966bbd79fea1ecff61bcc8a00e4665" @@ -24918,65 +23012,6 @@ metro@0.64.0, metro@^0.64.0: ws "^1.1.5" yargs "^15.3.1" -metro@^0.56.0, metro@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/metro/-/metro-0.56.4.tgz#be7e1380ee6ac3552c25ead8098eab261029e4d7" - integrity sha512-Kt3OQJQtQdts0JrKnyGdLpKHDjqYBgIfzvYrvfhmFCkKuZ8aqRlVnvpfjQ4/OBm0Fmm9NyyxbNRD9VIbj7WjnA== - dependencies: - "@babel/core" "^7.0.0" - "@babel/generator" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/plugin-external-helpers" "^7.0.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - absolute-path "^0.0.0" - async "^2.4.0" - babel-preset-fbjs "^3.1.2" - buffer-crc32 "^0.2.13" - chalk "^2.4.1" - concat-stream "^1.6.0" - connect "^3.6.5" - debug "^2.2.0" - denodeify "^1.2.1" - eventemitter3 "^3.0.0" - fbjs "^1.0.0" - fs-extra "^1.0.0" - graceful-fs "^4.1.3" - image-size "^0.6.0" - invariant "^2.2.4" - jest-haste-map "^24.7.1" - jest-worker "^24.6.0" - json-stable-stringify "^1.0.1" - lodash.throttle "^4.1.1" - merge-stream "^1.0.1" - metro-babel-register "^0.56.4" - metro-babel-transformer "^0.56.4" - metro-cache "^0.56.4" - metro-config "^0.56.4" - metro-core "^0.56.4" - metro-inspector-proxy "^0.56.4" - metro-minify-uglify "^0.56.4" - metro-react-native-babel-preset "^0.56.4" - metro-resolver "^0.56.4" - metro-source-map "^0.56.4" - metro-symbolicate "^0.56.4" - mime-types "2.1.11" - mkdirp "^0.5.1" - node-fetch "^2.2.0" - nullthrows "^1.1.0" - resolve "^1.5.0" - rimraf "^2.5.4" - serialize-error "^2.1.0" - source-map "^0.5.6" - temp "0.8.3" - throat "^4.1.0" - wordwrap "^1.0.0" - write-file-atomic "^1.2.0" - ws "^1.1.5" - xpipe "^1.0.5" - yargs "^9.0.0" - microevent.ts@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0" @@ -25344,18 +23379,6 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-db@~1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.23.0.tgz#a31b4070adaea27d732ea333740a64d0ec9a6659" - integrity sha1-oxtAcK2uon1zLqMzdApk0OyaZlk= - -mime-types@2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.11.tgz#c259c471bda808a85d6cd193b430a5fae4473b3c" - integrity sha1-wlnEcb2oCKhdbNGTtDCl+uRHOzw= - dependencies: - mime-db "~1.23.0" - mime-types@^2.1.12, mime-types@^2.1.19, mime-types@^2.1.25, mime-types@^2.1.27, mime-types@^2.1.30, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" @@ -25425,14 +23448,6 @@ min-indent@^1.0.0: resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== -mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== - dependencies: - "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" - mini-css-extract-plugin@^0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.5.0.tgz#ac0059b02b9692515a637115b0cc9fed3a35c7b0" @@ -25452,16 +23467,6 @@ mini-css-extract-plugin@^0.8.0: schema-utils "^1.0.0" webpack-sources "^1.1.0" -mini-store@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mini-store/-/mini-store-2.0.0.tgz#0843c048d6942ce55e3e78b1b67fc063022b5488" - integrity sha512-EG0CuwpQmX+XL4QVS0kxNwHW5ftSbhygu1qxQH0pipugjnPkbvkalCdQbEihMwtQY6d3MTN+MS0q+aurs+RfLQ== - dependencies: - hoist-non-react-statics "^2.3.1" - prop-types "^15.6.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.0.2" - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -25519,11 +23524,6 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -minimist@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= - minimist@^1.1.0, minimist@^1.1.3: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" @@ -25685,14 +23685,6 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mixin-object@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" - integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= - dependencies: - for-in "^0.1.3" - is-extendable "^0.1.1" - mkdirp-infer-owner@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" @@ -25765,12 +23757,12 @@ mold-source-map@~0.4.0: convert-source-map "^1.1.0" through "~2.2.7" -moment@2.x, moment@^2.18.1, moment@^2.24.0: +moment@^2.18.1: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== -morgan@^1.7.0, morgan@^1.9.0: +morgan@^1.7.0: version "1.9.1" resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59" integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA== @@ -25909,11 +23901,6 @@ mustache@^2.3.0: resolved "https://registry.yarnpkg.com/mustache/-/mustache-2.3.2.tgz#a6d4d9c3f91d13359ab889a812954f9230a3d0c5" integrity sha512-KpMNwdQsYz3O/SBS1qJ/o3sqUJ5wSb8gb0pul8CO0S56b9Y2ALm8zCfsjPXsqGFfoNBkDwZuZIAjhsZI03gYVQ== -mutationobserver-shim@^0.3.2: - version "0.3.7" - resolved "https://registry.yarnpkg.com/mutationobserver-shim/-/mutationobserver-shim-0.3.7.tgz#8bf633b0c0b0291a1107255ed32c13088a8c5bf3" - integrity sha512-oRIDTyZQU96nAiz2AQyngwx1e89iApl2hN5AOYwyxLUB47UYsU3Wv9lJWqH5y/QdiYkc5HQLi23ZNB3fELdHcQ== - mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -26037,32 +24024,6 @@ next@12.1.6: "@next/swc-win32-ia32-msvc" "12.1.6" "@next/swc-win32-x64-msvc" "12.1.6" -next@12.3.1: - version "12.3.1" - resolved "https://registry.yarnpkg.com/next/-/next-12.3.1.tgz#127b825ad2207faf869b33393ec8c75fe61e50f1" - integrity sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw== - dependencies: - "@next/env" "12.3.1" - "@swc/helpers" "0.4.11" - caniuse-lite "^1.0.30001406" - postcss "8.4.14" - styled-jsx "5.0.7" - use-sync-external-store "1.2.0" - optionalDependencies: - "@next/swc-android-arm-eabi" "12.3.1" - "@next/swc-android-arm64" "12.3.1" - "@next/swc-darwin-arm64" "12.3.1" - "@next/swc-darwin-x64" "12.3.1" - "@next/swc-freebsd-x64" "12.3.1" - "@next/swc-linux-arm-gnueabihf" "12.3.1" - "@next/swc-linux-arm64-gnu" "12.3.1" - "@next/swc-linux-arm64-musl" "12.3.1" - "@next/swc-linux-x64-gnu" "12.3.1" - "@next/swc-linux-x64-musl" "12.3.1" - "@next/swc-win32-arm64-msvc" "12.3.1" - "@next/swc-win32-ia32-msvc" "12.3.1" - "@next/swc-win32-x64-msvc" "12.3.1" - nice-try@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.4.tgz#d93962f6c52f2c1558c0fbda6d512819f1efe1c4" @@ -26095,17 +24056,6 @@ nocache@^2.1.0: resolved "https://registry.yarnpkg.com/nocache/-/nocache-2.1.0.tgz#120c9ffec43b5729b1d5de88cd71aa75a0ba491f" integrity sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q== -nock@11.7.2: - version "11.7.2" - resolved "https://registry.yarnpkg.com/nock/-/nock-11.7.2.tgz#4cee4fa838dc3635c074c5b3436bcdec7f7ee213" - integrity sha512-7swr5bL1xBZ5FctyubjxEVySXOSebyqcL7Vy1bx1nS9IUqQWj81cmKjVKJLr8fHhtzI1MV8nyCdENA/cGcY1+Q== - dependencies: - debug "^4.1.0" - json-stringify-safe "^5.0.1" - lodash "^4.17.13" - mkdirp "^0.5.0" - propagate "^2.0.0" - node-addon-api@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" @@ -26121,7 +24071,7 @@ node-ask@^1.0.1: resolved "https://registry.yarnpkg.com/node-ask/-/node-ask-1.0.1.tgz#caaa1076cc58e0364267a0903e3eadfac158396b" integrity sha1-yqoQdsxY4DZCZ6CQPj6t+sFYOWs= -node-dir@^0.1.10, node-dir@^0.1.17: +node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" integrity sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU= @@ -26133,15 +24083,7 @@ node-domexception@^1.0.0: resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== -node-fetch@1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.6.3.tgz#dc234edd6489982d58e8f0db4f695029abcd8c04" - integrity sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ= - dependencies: - encoding "^0.1.11" - is-stream "^1.0.1" - -node-fetch@2.6.7, node-fetch@^2.2.0, node-fetch@^2.5.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: +node-fetch@2.6.7, node-fetch@^2.2.0, node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== @@ -26301,17 +24243,6 @@ node-loggly-bulk@^2.2.4: moment "^2.18.1" request ">=2.76.0 <3.0.0" -node-notifier@^5.2.1, node-notifier@^5.4.2: - version "5.4.5" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.5.tgz#0cbc1a2b0f658493b4025775a13ad938e96091ef" - integrity sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ== - dependencies: - growly "^1.3.0" - is-wsl "^1.1.0" - semver "^5.5.0" - shellwords "^0.1.1" - which "^1.3.0" - node-object-hash@^1.2.0: version "1.4.2" resolved "https://registry.yarnpkg.com/node-object-hash/-/node-object-hash-1.4.2.tgz#385833d85b229902b75826224f6077be969a9e94" @@ -26388,11 +24319,6 @@ nomnom@~1.6.2: colors "0.5.x" underscore "~1.4.4" -noop-fn@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf" - integrity sha1-XzPUfxPSFQ35PgywNmmemC94/78= - nopt@1.0.10, nopt@~1.0.10: version "1.0.10" resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" @@ -26713,15 +24639,7 @@ nth-check@^2.0.0, nth-check@^2.0.1: dependencies: boolbase "^1.0.0" -null-loader@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/null-loader/-/null-loader-3.0.0.tgz#3e2b6c663c5bda8c73a54357d8fa0708dc61b245" - integrity sha512-hf5sNLl8xdRho4UPBOOeoIwT3WhjYcMUQm0zj44EhD6UscMAz72o2udpoDFBgykucdEDGIcd6SXbc/G6zssbzw== - dependencies: - loader-utils "^1.2.3" - schema-utils "^1.0.0" - -nullthrows@1.1.1, nullthrows@^1.1.0, nullthrows@^1.1.1: +nullthrows@1.1.1, nullthrows@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/nullthrows/-/nullthrows-1.1.1.tgz#7818258843856ae971eae4208ad7d7eb19a431b1" integrity sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw== @@ -26813,21 +24731,11 @@ ob1@0.64.0: resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.64.0.tgz#f254a55a53ca395c4f9090e28a85483eac5eba19" integrity sha512-CO1N+5dhvy+MoAwxz8+fymEUcwsT4a+wHhrHFb02LppcJdHxgcBWviwEhUwKOD2kLMQ7ijrrzybOqpGcqEtvpQ== -ob1@^0.56.4: - version "0.56.4" - resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.56.4.tgz#c4acb3baa42f4993a44b35b2da7c8ef443dcccec" - integrity sha512-URgFof9z2wotiYFsqlydXtQfGV81gvBI2ODy64xfd3vPo+AYom5PVDX4t4zn23t/O+S2IxqApSQM8uJAybmz7w== - -object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -object-assign@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2" - integrity sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I= - object-copy@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" @@ -26938,13 +24846,6 @@ obuf@^1.0.0, obuf@^1.1.2: resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -omit.js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/omit.js/-/omit.js-1.0.2.tgz#91a14f0eba84066dfa015bf30e474c47f30bc858" - integrity sha512-/QPc6G2NS+8d4L/cQhbk6Yit1WTB6Us2g84A7A/1+w9d/eRGHyEqC5kkQtHVoHZ5NFWGG7tUGgrhVZwgZanKrQ== - dependencies: - babel-runtime "^6.23.0" - on-finished@2.4.1, on-finished@^2.3.0: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -27016,18 +24917,6 @@ open@^8.0.4, open@^8.3.0, open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -opencollective@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/opencollective/-/opencollective-1.0.3.tgz#aee6372bc28144583690c3ca8daecfc120dd0ef1" - integrity sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE= - dependencies: - babel-polyfill "6.23.0" - chalk "1.1.3" - inquirer "3.0.6" - minimist "1.2.0" - node-fetch "1.6.3" - opn "4.0.2" - opener@1.5.2, opener@^1.5.1, opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -27038,14 +24927,6 @@ openurl@1.1.1: resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387" integrity sha1-OHW0sO96UsFW8NtB1GCduw+Us4c= -opn@4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" - integrity sha1-erwi5kTf9jsKltWrfyeQwPAavJU= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - opn@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -27179,16 +25060,7 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-locale@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-2.1.0.tgz#42bc2900a6b5b8bd17376c8e882b65afccf24bf2" - integrity sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA== - dependencies: - execa "^0.7.0" - lcid "^1.0.0" - mem "^1.1.0" - -os-locale@^3.0.0, os-locale@^3.1.0: +os-locale@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== @@ -27242,13 +25114,6 @@ p-defer@^1.0.0: resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha1-kw89Et0fUOdDRFeiLNbwSsatf3E= - dependencies: - p-reduce "^1.0.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -27271,7 +25136,7 @@ p-limit@^1.0.0, p-limit@^1.1.0: dependencies: p-try "^1.0.0" -p-limit@^2.0.0, p-limit@^2.2.0, p-limit@^2.2.1: +p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== @@ -27350,11 +25215,6 @@ p-queue@^6.6.2: eventemitter3 "^4.0.4" p-timeout "^3.2.0" -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - p-reduce@^2.0.0, p-reduce@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" @@ -27677,11 +25537,6 @@ parse-ms@^2.1.0: resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-2.1.0.tgz#348565a753d4391fa524029956b172cb7753097d" integrity sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA== -parse-node-version@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" - integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== - parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" @@ -27874,18 +25729,6 @@ path-to-regexp@0.1.7: resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= -path-to-regexp@^1.7.0, path-to-regexp@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - -path-to-regexp@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-2.4.0.tgz#35ce7f333d5616f1c1e1bfe266c3aba2e5b2e704" - integrity sha512-G6zHoVqC6GGTQkZwF4lkuEyMbVOjoBKAEybQUypI1WTkqinCOrq2x6U2+phkJ1XsEMTy4LjtwPI7HW+NVrRR2w== - path-to-regexp@^6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" @@ -27900,13 +25743,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -path-type@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" - integrity sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM= - dependencies: - pify "^2.0.0" - path-type@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" @@ -28069,7 +25905,7 @@ places.js@1.17.1: events "^3.0.0" insert-css "^2.0.0" -plist@^3.0.0, plist@^3.0.1, plist@^3.0.4: +plist@^3.0.1, plist@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/plist/-/plist-3.0.4.tgz#a62df837e3aed2bb3b735899d510c4f186019cbe" integrity sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg== @@ -28077,17 +25913,6 @@ plist@^3.0.0, plist@^3.0.1, plist@^3.0.4: base64-js "^1.5.1" xmlbuilder "^9.0.7" -plugin-error@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/plugin-error/-/plugin-error-0.1.2.tgz#3b9bb3335ccf00f425e07437e19276967da47ace" - integrity sha1-O5uzM1zPAPQl4HQ34ZJ2ln2kes4= - dependencies: - ansi-cyan "^0.1.1" - ansi-red "^0.1.1" - arr-diff "^1.0.1" - arr-union "^2.0.1" - extend-shallow "^1.1.2" - pn@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" @@ -28933,15 +26758,6 @@ postcss-values-parser@^2.0.0, postcss-values-parser@^2.0.1: indexes-of "^1.0.1" uniq "^1.0.1" -postcss@8.4.14: - version "8.4.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" - integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== - dependencies: - nanoid "^3.3.4" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@8.4.20, postcss@^8.1.10, postcss@^8.2.4, postcss@^8.3.11, postcss@^8.4.14, postcss@^8.4.16, postcss@^8.4.18, postcss@^8.4.19: version "8.4.20" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56" @@ -29009,11 +26825,6 @@ posthtml@^0.16.4, posthtml@^0.16.5: posthtml-parser "^0.10.0" posthtml-render "^3.0.0" -pouchdb-collections@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359" - integrity sha1-/mOhfal3YRq+98uAJssalVP9g1k= - preact-render-to-string@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-4.1.0.tgz#70d98a8385cb86558366c558aad7311ebecb881d" @@ -29125,34 +26936,6 @@ pretty-error@^2.0.2, pretty-error@^2.1.1: renderkid "^2.0.1" utila "~0.4" -pretty-format@^23.6.0: - version "23.6.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" - integrity sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== - dependencies: - ansi-regex "^3.0.0" - ansi-styles "^3.2.0" - -pretty-format@^24.7.0, pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - -pretty-format@^25.1.0: - version "25.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" - integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== - dependencies: - "@jest/types" "^25.5.0" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^16.12.0" - pretty-format@^26.5.2, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -29340,7 +27123,7 @@ prompts@2.4.0: kleur "^3.0.3" sisteransi "^1.0.5" -prompts@^2.0.1, prompts@^2.2.1, prompts@^2.3.2, prompts@^2.4.0, prompts@^2.4.2: +prompts@^2.0.1, prompts@^2.3.2, prompts@^2.4.0, prompts@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== @@ -29372,7 +27155,7 @@ prop-types@15.7.2: object-assign "^4.1.1" react-is "^16.8.1" -prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.5.9, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.0, prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -29381,11 +27164,6 @@ prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, pr object-assign "^4.1.1" react-is "^16.13.1" -propagate@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/propagate/-/propagate-2.0.1.tgz#40cdedab18085c792334e64f0ac17256d38f9a45" - integrity sha512-vGrhOavPSTz4QVNuBNdcNXePNdNMaO1xj9yBeH1ScQPjk/rhg9sSlCXPhMkFuaNNW/syTvYqsnbIJxMBfRbbag== - proper-lockfile@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" @@ -29645,7 +27423,7 @@ qrcode-terminal@0.11.0: resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz#ffc6c28a2fc0bfb47052b47e23f4f446a5fbdb9e" integrity sha1-/8bCii/Av7RwUrR+I/T0RqX7254= -qs@6.11.0, qs@^6.10.0, qs@^6.5.0, qs@^6.6.0: +qs@6.11.0, qs@^6.10.0, qs@^6.6.0: version "6.11.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== @@ -29674,7 +27452,7 @@ qs@^6.11.0: dependencies: side-channel "^1.0.4" -query-string@^4.1.0, query-string@^4.2.2: +query-string@^4.1.0: version "4.3.4" resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" integrity sha1-u7aTucqRXCMlFbIosaArYJBD2+s= @@ -29682,16 +27460,6 @@ query-string@^4.1.0, query-string@^4.2.2: object-assign "^4.1.0" strict-uri-encode "^1.0.0" -query-string@^6.13.6: - version "6.14.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" - integrity sha512-XDxAeVmpfu1/6IjyT/gXHOl+S0vQ9owggJ30hhWKdHAsNPOcasn5o9BW0eejZqL2e4vMjhAxoW3jVHcD6mbcYw== - dependencies: - decode-uri-component "^0.2.0" - filter-obj "^1.1.0" - split-on-first "^1.0.0" - strict-uri-encode "^2.0.0" - querystring-es3@^0.2.0, querystring-es3@^0.2.1, querystring-es3@~0.2.0: version "0.2.1" resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" @@ -29736,7 +27504,7 @@ quick-lru@^5.1.1: resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== -raf@^3.4.0, raf@^3.4.1: +raf@^3.4.1: version "3.4.1" resolved "https://registry.yarnpkg.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -29819,441 +27587,6 @@ raw-loader@^3.1.0: loader-utils "^1.1.0" schema-utils "^2.0.1" -rc-align@^2.4.0, rc-align@^2.4.1: - version "2.4.5" - resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.4.5.tgz#c941a586f59d1017f23a428f0b468663fb7102ab" - integrity sha512-nv9wYUYdfyfK+qskThf4BQUSIadeI/dCsfaMZfNEoxm9HwOIioQ+LyqmMK6jWHAZQgOzMLaqawhuBXlF63vgjw== - dependencies: - babel-runtime "^6.26.0" - dom-align "^1.7.0" - prop-types "^15.5.8" - rc-util "^4.0.4" - -rc-animate@2.x, rc-animate@^2.10.1, rc-animate@^2.3.0, rc-animate@^2.6.0, rc-animate@^2.8.2, rc-animate@^2.8.3: - version "2.11.1" - resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-2.11.1.tgz#2666eeb6f1f2a495a13b2af09e236712278fdb2c" - integrity sha512-1NyuCGFJG/0Y+9RKh5y/i/AalUCA51opyyS/jO2seELpgymZm2u9QV3xwODwEuzkmeQ1BDPxMLmYLcTJedPlkQ== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - css-animation "^1.3.2" - prop-types "15.x" - raf "^3.4.0" - rc-util "^4.15.3" - react-lifecycles-compat "^3.0.4" - -rc-animate@^3.0.0-rc.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/rc-animate/-/rc-animate-3.1.1.tgz#defdd863f56816c222534e4dc68feddecd081386" - integrity sha512-8wg2Zg3EETy0k/9kYuis30NJNQg1D6/WSQwnCiz6SvyxQXNet/rVraRz3bPngwY6rcU2nlRvoShiYOorXyF7Sg== - dependencies: - "@ant-design/css-animation" "^1.7.2" - classnames "^2.2.6" - raf "^3.4.0" - rc-util "^4.15.3" - -rc-calendar@~9.15.5: - version "9.15.11" - resolved "https://registry.yarnpkg.com/rc-calendar/-/rc-calendar-9.15.11.tgz#ce1e5ea8e4d77435be66a8c77db12f1f0f9a345f" - integrity sha512-qv0VXfAAnysMWJigxaP6se4bJHvr17D9qsLbi8BOpdgEocsS0RkgY1IUiFaOVYKJDy/EyLC447O02sV/y5YYBg== - dependencies: - babel-runtime "6.x" - classnames "2.x" - moment "2.x" - prop-types "^15.5.8" - rc-trigger "^2.2.0" - rc-util "^4.1.1" - react-lifecycles-compat "^3.0.4" - -rc-cascader@~0.17.4: - version "0.17.5" - resolved "https://registry.yarnpkg.com/rc-cascader/-/rc-cascader-0.17.5.tgz#4fde91d23b7608c420263c38eee9c0687f80f7dc" - integrity sha512-WYMVcxU0+Lj+xLr4YYH0+yXODumvNXDcVEs5i7L1mtpWwYkubPV/zbQpn+jGKFCIW/hOhjkU4J1db8/P/UKE7A== - dependencies: - array-tree-filter "^2.1.0" - prop-types "^15.5.8" - rc-trigger "^2.2.0" - rc-util "^4.0.4" - react-lifecycles-compat "^3.0.4" - shallow-equal "^1.0.0" - warning "^4.0.1" - -rc-checkbox@~2.1.6: - version "2.1.8" - resolved "https://registry.yarnpkg.com/rc-checkbox/-/rc-checkbox-2.1.8.tgz#eedd9ef9c2f3af5b3b8e5cde5254aa89ad1a880a" - integrity sha512-6qOgh0/by0nVNASx6LZnhRTy17Etcgav+IrI7kL9V9kcDZ/g7K14JFlqrtJ3NjDq/Kyn+BPI1st1XvbkhfaJeg== - dependencies: - babel-runtime "^6.23.0" - classnames "2.x" - prop-types "15.x" - react-lifecycles-compat "^3.0.4" - -rc-collapse@~1.11.3: - version "1.11.8" - resolved "https://registry.yarnpkg.com/rc-collapse/-/rc-collapse-1.11.8.tgz#66a40089d469519e9424009ab1c927e214041d80" - integrity sha512-8EhfPyScTYljkbRuIoHniSwZagD5UPpZ3CToYgoNYWC85L2qCbPYF7+OaC713FOrIkp6NbfNqXsITNxmDAmxog== - dependencies: - classnames "2.x" - css-animation "1.x" - prop-types "^15.5.6" - rc-animate "2.x" - react-is "^16.7.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - -rc-dialog@~7.5.2: - version "7.5.14" - resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-7.5.14.tgz#3e85ed8a6f3ae17cf5082b590b9c366f70ebf5dc" - integrity sha512-gmEukl2iU2K74G2g66rVH6yOCwvLbVWqmEClbRO47Iec/stFyaDXCkvJmBb5vJcAWomQwaU4yZ9muRBW4u9AfA== - dependencies: - babel-runtime "6.x" - rc-animate "2.x" - rc-util "^4.8.1" - -rc-drawer@~2.0.1: - version "2.0.9" - resolved "https://registry.yarnpkg.com/rc-drawer/-/rc-drawer-2.0.9.tgz#d1d07b74416b50d22082b5886ec061be2b2b15fc" - integrity sha512-7qwEND3TLvJeyuUvZfMDkL2pHsR/XHX5HvoaBlIH9mTcFWBmMNrvYGDuGHgGsdNKZZgIBwlkvl5vhckydTUc9Q== - dependencies: - babel-runtime "6.x" - classnames "^2.2.5" - rc-util "^4.7.0" - react-lifecycles-compat "^3.0.4" - -rc-dropdown@~2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/rc-dropdown/-/rc-dropdown-2.4.1.tgz#aaef6eb3a5152cdd9982895c2a78d9b5f046cdec" - integrity sha512-p0XYn0wrOpAZ2fUGE6YJ6U8JBNc5ASijznZ6dkojdaEfQJAeZtV9KMEewhxkVlxGSbbdXe10ptjBlTEW9vEwEg== - dependencies: - babel-runtime "^6.26.0" - classnames "^2.2.6" - prop-types "^15.5.8" - rc-trigger "^2.5.1" - react-lifecycles-compat "^3.0.2" - -rc-editor-core@~0.8.3: - version "0.8.10" - resolved "https://registry.yarnpkg.com/rc-editor-core/-/rc-editor-core-0.8.10.tgz#6f215bc5df9c33ffa9f6c5b30ca73a7dabe8ab7c" - integrity sha512-T3aHpeMCIYA1sdAI7ynHHjXy5fqp83uPlD68ovZ0oClTSc3tbHmyCxXlA+Ti4YgmcpCYv7avF6a+TIbAka53kw== - dependencies: - babel-runtime "^6.26.0" - classnames "^2.2.5" - draft-js "^0.10.0" - immutable "^3.7.4" - lodash "^4.16.5" - prop-types "^15.5.8" - setimmediate "^1.0.5" - -rc-editor-mention@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/rc-editor-mention/-/rc-editor-mention-1.1.13.tgz#9f1cab1065f86b01523840321790c2ab12ac5e8b" - integrity sha512-3AOmGir91Fi2ogfRRaXLtqlNuIwQpvla7oUnGHS1+3eo7b+fUp5IlKcagqtwUBB5oDNofoySXkLBxzWvSYNp/Q== - dependencies: - babel-runtime "^6.23.0" - classnames "^2.2.5" - dom-scroll-into-view "^1.2.0" - draft-js "~0.10.0" - immutable "~3.7.4" - prop-types "^15.5.8" - rc-animate "^2.3.0" - rc-editor-core "~0.8.3" - -rc-form@^2.4.5: - version "2.4.12" - resolved "https://registry.yarnpkg.com/rc-form/-/rc-form-2.4.12.tgz#4ee8711e90a2584baa7ac276de96bee0d9b0f5f1" - integrity sha512-sHfyWRrnjCHkeCYfYAGop2GQBUC6CKMPcJF9h/gL/vTmZB/RN6fNOGKjXrXjFbwFwKXUWBoPtIDDDmXQW9xNdw== - dependencies: - async-validator "~1.11.3" - babel-runtime "6.x" - create-react-class "^15.5.3" - dom-scroll-into-view "1.x" - hoist-non-react-statics "^3.3.0" - lodash "^4.17.4" - rc-util "^4.15.3" - react-is "^16.13.1" - warning "^4.0.3" - -rc-hammerjs@~0.6.0: - version "0.6.10" - resolved "https://registry.yarnpkg.com/rc-hammerjs/-/rc-hammerjs-0.6.10.tgz#1831a3bd8f2199700bfcc5ad6b20a35630aeb5e0" - integrity sha512-Vgh9qIudyN5CHRop4M+v+xUniQBFWXKrsJxQRVtJOi2xgRrCeI52/bkpaL5HWwUhqTK9Ayq0n7lYTItT6ld5rg== - dependencies: - babel-runtime "6.x" - hammerjs "^2.0.8" - prop-types "^15.5.9" - -rc-input-number@~4.5.0: - version "4.5.9" - resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-4.5.9.tgz#1cbf735e24fe23c4eb9a4301031720b95f2a3e3d" - integrity sha512-wAT4EBpLDW4+27c935k4F1JLk+gnhyGBkpzBmtkNvIHLG8yTndZSJ2bFfSYfkA6C82IxmAztXs3ffCeUd/rkbg== - dependencies: - babel-runtime "6.x" - classnames "^2.2.0" - prop-types "^15.5.7" - rc-util "^4.5.1" - rmc-feedback "^2.0.0" - -rc-mentions@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/rc-mentions/-/rc-mentions-0.4.2.tgz#c18ab701efb9e4b75b3851a0c0d2dd698640e246" - integrity sha512-DTZurQzacLXOfVuiHydGzqkq7cFMHXF18l2jZ9PhWUn2cqvOSY3W4osN0Pq29AOMOBpcxdZCzgc7Lb0r/bgkDw== - dependencies: - "@ant-design/create-react-context" "^0.2.4" - classnames "^2.2.6" - rc-menu "^7.4.22" - rc-trigger "^2.6.2" - rc-util "^4.6.0" - react-lifecycles-compat "^3.0.4" - -rc-menu@^7.3.0, rc-menu@^7.4.22: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-7.5.5.tgz#78cdc817d86fc353a1430b864d3d96c7489600ca" - integrity sha512-4YJXJgrpUGEA1rMftXN7bDhrV5rPB8oBJoHqT+GVXtIWCanfQxEnM3fmhHQhatL59JoAFMZhJaNzhJIk4FUWCQ== - dependencies: - classnames "2.x" - dom-scroll-into-view "1.x" - mini-store "^2.0.0" - mutationobserver-shim "^0.3.2" - rc-animate "^2.10.1" - rc-trigger "^2.3.0" - rc-util "^4.13.0" - resize-observer-polyfill "^1.5.0" - shallowequal "^1.1.0" - -rc-menu@~7.4.23: - version "7.4.32" - resolved "https://registry.yarnpkg.com/rc-menu/-/rc-menu-7.4.32.tgz#71409216daaa9f43d8acc4530628879740d63708" - integrity sha512-9/ySqniMdvhUhfiUFmqK3hLffYIdeR2nrDDNvXksTCc2ZYd1JmOWF16yO7iYyDPLZM33NU3Qw6EPZd21+FxJsQ== - dependencies: - classnames "2.x" - dom-scroll-into-view "1.x" - mini-store "^2.0.0" - mutationobserver-shim "^0.3.2" - rc-animate "2.x" - rc-trigger "^2.3.0" - rc-util "^4.13.0" - resize-observer-polyfill "^1.5.0" - -rc-notification@~3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/rc-notification/-/rc-notification-3.3.1.tgz#0baa3e70f8d40ab015ce8fa78c260c490fc7beb4" - integrity sha512-U5+f4BmBVfMSf3OHSLyRagsJ74yKwlrQAtbbL5ijoA0F2C60BufwnOcHG18tVprd7iaIjzZt1TKMmQSYSvgrig== - dependencies: - babel-runtime "6.x" - classnames "2.x" - prop-types "^15.5.8" - rc-animate "2.x" - rc-util "^4.0.4" - -rc-pagination@~1.20.5: - version "1.20.15" - resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-1.20.15.tgz#ccb4cd0e9bd4e47f72f29ea432c0350bf7b3d807" - integrity sha512-/Xr4/3GOa1DtL8iCYl7qRUroEMrRDhZiiuHwcVFfSiwa9LYloMlUWcOJsnr8LN6A7rLPdm3/CHStUNeYd+2pKw== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - prop-types "^15.5.7" - react-lifecycles-compat "^3.0.4" - -rc-progress@~2.5.0: - version "2.5.3" - resolved "https://registry.yarnpkg.com/rc-progress/-/rc-progress-2.5.3.tgz#00f01b95bdbe1856d3a5f82242051902e8b7a8e7" - integrity sha512-K2fa4CnqGehLZoMrdmBeZ86ONSTVcdk5FlqetbwJ3R/+42XfqhwQVOjWp2MH4P7XSQOMAGcNOy1SFfCP3415sg== - dependencies: - babel-runtime "6.x" - prop-types "^15.5.8" - -rc-rate@~2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/rc-rate/-/rc-rate-2.5.1.tgz#55fc5fd23ea9dcc72250b9a889803479f4842961" - integrity sha512-3iJkNJT8xlHklPCdeZtUZmJmRVUbr6AHRlfSsztfYTXVlHrv2TcPn3XkHsH+12j812WVB7gvilS2j3+ffjUHXg== - dependencies: - classnames "^2.2.5" - prop-types "^15.5.8" - rc-util "^4.3.0" - react-lifecycles-compat "^3.0.4" - -rc-select@~9.2.0: - version "9.2.3" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-9.2.3.tgz#64340e2d6ef64e8bc3cfc6f468ffd28625589ac2" - integrity sha512-WhswxOMWiNnkXRbxyrj0kiIvyCfo/BaRPaYbsDetSIAU2yEDwKHF798blCP5u86KLOBKBvtxWLFCkSsQw1so5w== - dependencies: - babel-runtime "^6.23.0" - classnames "2.x" - component-classes "1.x" - dom-scroll-into-view "1.x" - prop-types "^15.5.8" - raf "^3.4.0" - rc-animate "2.x" - rc-menu "^7.3.0" - rc-trigger "^2.5.4" - rc-util "^4.0.4" - react-lifecycles-compat "^3.0.2" - warning "^4.0.2" - -rc-slider@~8.6.11: - version "8.6.13" - resolved "https://registry.yarnpkg.com/rc-slider/-/rc-slider-8.6.13.tgz#88a8150c2dda6709f3f119135de11fba80af765b" - integrity sha512-fCUe8pPn8n9pq1ARX44nN2nzJoATtna4x/PdskUrxIvZXN8ja7HuceN/hq6kokZjo3FBD2B1yMZvZh6oi68l6Q== - dependencies: - babel-runtime "6.x" - classnames "^2.2.5" - prop-types "^15.5.4" - rc-tooltip "^3.7.0" - rc-util "^4.0.4" - shallowequal "^1.0.1" - warning "^4.0.3" - -rc-steps@~3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/rc-steps/-/rc-steps-3.5.0.tgz#36b2a7f1f49907b0d90363884b18623caf9fb600" - integrity sha512-2Vkkrpa7PZbg7qPsqTNzVDov4u78cmxofjjnIHiGB9+9rqKS8oTLPzbW2uiWDr3Lk+yGwh8rbpGO1E6VAgBCOg== - dependencies: - babel-runtime "^6.23.0" - classnames "^2.2.3" - lodash "^4.17.5" - prop-types "^15.5.7" - -rc-switch@~1.9.0: - version "1.9.2" - resolved "https://registry.yarnpkg.com/rc-switch/-/rc-switch-1.9.2.tgz#7921c766411fe9a6426510c3429022d6ba4dfde2" - integrity sha512-qaK7mY4FLDKy99Hq3A1tf8CcqfzKtHp9LPX8WTnZ0MzdHCTneSARb1XD7Eqeu8BactasYGsi2bF9p18Q+/5JEw== - dependencies: - classnames "^2.2.1" - prop-types "^15.5.6" - react-lifecycles-compat "^3.0.4" - -rc-table@~6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-6.7.0.tgz#8aca002f84a43a2d51a4fcda0f7a51694154286d" - integrity sha512-zzu7UtEHLTzZibB1EOoeKQejH21suoxRQx3evlGGLwz5NUh2HDUHobSr12z5Kd8EPr1+y/LPzXJdX1ctFPC+hA== - dependencies: - babel-runtime "6.x" - classnames "^2.2.5" - component-classes "^1.2.6" - lodash "^4.17.5" - mini-store "^2.0.0" - prop-types "^15.5.8" - rc-util "^4.0.4" - react-lifecycles-compat "^3.0.2" - shallowequal "^1.0.2" - warning "^3.0.0" - -rc-tabs@~9.6.4: - version "9.6.7" - resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-9.6.7.tgz#c546115a351f5ed779ea5524143157f48ee0c015" - integrity sha512-OXbDOgaqv2MGK9QaDi6cdva6bNz3XGw+M9BHQpm1gTGmVQEGx5VcclDClH/3xobIzooxy8hrxg/s0rTlgDnC2w== - dependencies: - "@ant-design/create-react-context" "^0.2.4" - babel-runtime "6.x" - classnames "2.x" - lodash "^4.17.5" - prop-types "15.x" - raf "^3.4.1" - rc-hammerjs "~0.6.0" - rc-util "^4.0.4" - react-lifecycles-compat "^3.0.4" - resize-observer-polyfill "^1.5.1" - warning "^4.0.3" - -rc-time-picker@~3.7.1: - version "3.7.3" - resolved "https://registry.yarnpkg.com/rc-time-picker/-/rc-time-picker-3.7.3.tgz#65a8de904093250ae9c82b02a4905e0f995e23e2" - integrity sha512-Lv1Mvzp9fRXhXEnRLO4nW6GLNxUkfAZ3RsiIBsWjGjXXvMNjdr4BX/ayElHAFK0DoJqOhm7c5tjmIYpEOwcUXg== - dependencies: - classnames "2.x" - moment "2.x" - prop-types "^15.5.8" - raf "^3.4.1" - rc-trigger "^2.2.0" - react-lifecycles-compat "^3.0.4" - -rc-tooltip@^3.7.0, rc-tooltip@~3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/rc-tooltip/-/rc-tooltip-3.7.3.tgz#280aec6afcaa44e8dff0480fbaff9e87fc00aecc" - integrity sha512-dE2ibukxxkrde7wH9W8ozHKUO4aQnPZ6qBHtrTH9LoO836PjDdiaWO73fgPB05VfJs9FbZdmGPVEbXCeOP99Ww== - dependencies: - babel-runtime "6.x" - prop-types "^15.5.8" - rc-trigger "^2.2.2" - -rc-tree-select@~2.9.1: - version "2.9.4" - resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-2.9.4.tgz#6aa794e1f0e65c66c406aa0a2a0e74fd0a557b09" - integrity sha512-0HQkXAN4XbfBW20CZYh3G+V+VMrjX42XRtDCpyv6PDUm5vikC0Ob682ZBCVS97Ww2a5Hf6Ajmu0ahWEdIEpwhg== - dependencies: - classnames "^2.2.1" - dom-scroll-into-view "^1.2.1" - prop-types "^15.5.8" - raf "^3.4.0" - rc-animate "^2.8.2" - rc-tree "~2.1.0" - rc-trigger "^3.0.0" - rc-util "^4.5.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.0.2" - warning "^4.0.1" - -rc-tree@~2.1.0: - version "2.1.4" - resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-2.1.4.tgz#ef759f3e799a21b43c1ecf9c794ea1c14e70b59b" - integrity sha512-Xey794Iavgs8YldFlXcZLOhfcIhlX5Oz/yfKufknBXf2AlZCOkc7aHqSM9uTF7fBPtTGPhPxNEfOqHfY7b7xng== - dependencies: - "@ant-design/create-react-context" "^0.2.4" - classnames "2.x" - prop-types "^15.5.8" - rc-animate "^2.6.0" - rc-util "^4.5.1" - react-lifecycles-compat "^3.0.4" - warning "^4.0.3" - -rc-trigger@^2.2.0, rc-trigger@^2.2.2, rc-trigger@^2.3.0, rc-trigger@^2.5.1, rc-trigger@^2.5.4, rc-trigger@^2.6.2: - version "2.6.5" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-2.6.5.tgz#140a857cf28bd0fa01b9aecb1e26a50a700e9885" - integrity sha512-m6Cts9hLeZWsTvWnuMm7oElhf+03GOjOLfTuU0QmdB9ZrW7jR2IpI5rpNM7i9MvAAlMAmTx5Zr7g3uu/aMvZAw== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - prop-types "15.x" - rc-align "^2.4.0" - rc-animate "2.x" - rc-util "^4.4.0" - react-lifecycles-compat "^3.0.4" - -rc-trigger@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-3.0.0.tgz#f6d9b1da8a26b2b2d1d912a06876c1a486f5980f" - integrity sha512-hQxbbJpo23E2QnYczfq3Ec5J5tVl2mUDhkqxrEsQAqk16HfADQg+iKNWzEYXyERSncdxfnzYuaBgy764mNRzTA== - dependencies: - babel-runtime "6.x" - classnames "^2.2.6" - prop-types "15.x" - raf "^3.4.0" - rc-align "^2.4.1" - rc-animate "^3.0.0-rc.1" - rc-util "^4.15.7" - -rc-upload@~2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/rc-upload/-/rc-upload-2.7.0.tgz#f279b758655eb5f99ebf82a5a2648d80d88e0ff4" - integrity sha512-Oh9EJB4xE8MQUZ2D0OUST3UMIBjHjnO2IjPNW/cbPredxZz+lzbLPCZxcxRwUwu1gt0LA968UWXAgT1EvZdFfA== - dependencies: - babel-runtime "6.x" - classnames "^2.2.5" - prop-types "^15.5.7" - warning "4.x" - -rc-util@^4.0.4, rc-util@^4.1.1, rc-util@^4.10.0, rc-util@^4.13.0, rc-util@^4.15.3, rc-util@^4.15.7, rc-util@^4.3.0, rc-util@^4.4.0, rc-util@^4.5.0, rc-util@^4.5.1, rc-util@^4.6.0, rc-util@^4.7.0, rc-util@^4.8.1: - version "4.21.1" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-4.21.1.tgz#88602d0c3185020aa1053d9a1e70eac161becb05" - integrity sha512-Z+vlkSQVc1l8O2UjR3WQ+XdWlhj5q9BMQNLk2iOBch75CqPfrJyGtcWMcnhRlNuDu0Ndtt4kLVO8JI8BrABobg== - dependencies: - add-dom-event-listener "^1.1.0" - prop-types "^15.5.10" - react-is "^16.12.0" - react-lifecycles-compat "^3.0.4" - shallowequal "^1.1.0" - rc9@^1.2.0: version "1.2.4" resolved "https://registry.yarnpkg.com/rc9/-/rc9-1.2.4.tgz#a625f5ec63a54eebd66114eb9c6ce9a6c54dfac8" @@ -30273,24 +27606,6 @@ rc@^1.0.1, rc@^1.1.6, rc@^1.2.7, rc@^1.2.8, rc@~1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-autosuggest@9.4.3: - version "9.4.3" - resolved "https://registry.yarnpkg.com/react-autosuggest/-/react-autosuggest-9.4.3.tgz#eb46852422a48144ab9f39fb5470319222f26c7c" - integrity sha512-wFbp5QpgFQRfw9cwKvcgLR8theikOUkv8PFsuLYqI2PUgVlx186Cz8MYt5bLxculi+jxGGUUVt+h0esaBZZouw== - dependencies: - prop-types "^15.5.10" - react-autowhatever "^10.1.2" - shallow-equal "^1.0.0" - -react-autowhatever@^10.1.2: - version "10.1.2" - resolved "https://registry.yarnpkg.com/react-autowhatever/-/react-autowhatever-10.1.2.tgz#200ffc41373b2189e3f6140ac7bdb82363a79fd3" - integrity sha512-+0XgELT1LF7hHEJv5H5Zwkfb4Q1rqmMZZ5U/XJ2J+UcSPRKnG6CqEjXUJ+hYLXDHgvDqwEN5PBdxczD5rHvOuA== - dependencies: - prop-types "^15.5.8" - react-themeable "^1.1.0" - section-iterator "^2.0.0" - react-clientside-effect@^1.2.2: version "1.2.5" resolved "https://registry.yarnpkg.com/react-clientside-effect/-/react-clientside-effect-1.2.5.tgz#e2c4dc3c9ee109f642fac4f5b6e9bf5bcd2219a3" @@ -30298,11 +27613,6 @@ react-clientside-effect@^1.2.2: dependencies: "@babel/runtime" "^7.12.13" -react-clone-referenced-element@*: - version "1.1.1" - resolved "https://registry.yarnpkg.com/react-clone-referenced-element/-/react-clone-referenced-element-1.1.1.tgz#8d76727dc0459788e461741e804a512d20757381" - integrity sha512-LZBPvQV8W0B5dFzXFu+D3Tpil8YHS8tO00iFsfXcTLdtpuH7XyvaHqHcoz4hd4uNPQCZ30fceh+s7mLznzMXvg== - react-color@^2.17.0: version "2.19.3" resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" @@ -30321,16 +27631,6 @@ react-colorful@^5.1.2: resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.4.0.tgz#e05e602469f9768234f29c1bad9ec1f4e86145a2" integrity sha512-k7QJXuQGWevr/V8hoMJ1wBW9i2CVhBdDXpBf3jy/AAtzVyYtsFqEAT+y+NOGiSG1cmnGTreqm5EFLXlVaKbPLQ== -react-compound-slider@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/react-compound-slider/-/react-compound-slider-2.2.0.tgz#d79adb60d3b42fb2f2e6a88d7630795244a434a2" - integrity sha512-HFYKtbL1MZyrBrK29Y7KBRU2INnPqX0yODdcWd539sif7eLPoG2uEULloga2ju7l7zcIWzJcehO12WrieHDIiA== - dependencies: - "@babel/runtime" "^7.5.4" - d3-array "^1.2.4" - prop-types "^15.7.2" - warning "^3.0.0" - react-compound-slider@3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/react-compound-slider/-/react-compound-slider-3.4.0.tgz#0367befe1367bb7968b38d0cbf07db6192b3c57e" @@ -30401,14 +27701,6 @@ react-dev-utils@~11.0.1: strip-ansi "6.0.0" text-table "0.2.0" -react-devtools-core@^3.6.3: - version "3.6.3" - resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-3.6.3.tgz#977d95b684c6ad28205f0c62e1e12c5f16675814" - integrity sha512-+P+eFy/yo8Z/UH9J0DqHZuUM5+RI2wl249TNvMx3J2jpUomLQa4Zxl56GEotGfw3PIP1eI+hVf1s53FlUONStQ== - dependencies: - shell-quote "^1.6.1" - ws "^3.3.1" - react-devtools-core@^4.6.0: version "4.23.0" resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.23.0.tgz#dff9d12202a472ef62632203d6de3877dc6e58be" @@ -30417,31 +27709,6 @@ react-devtools-core@^4.6.0: shell-quote "^1.6.1" ws "^7" -react-docgen@^5.0.0: - version "5.4.3" - resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.4.3.tgz#7d297f73b977d0c7611402e5fc2a168acf332b26" - integrity sha512-xlLJyOlnfr8lLEEeaDZ+X2J/KJoe6Nr9AzxnkdQWush5hz2ZSu66w6iLMOScMmxoSHWpWMn+k3v5ZiyCfcWsOA== - dependencies: - "@babel/core" "^7.7.5" - "@babel/generator" "^7.12.11" - "@babel/runtime" "^7.7.6" - ast-types "^0.14.2" - commander "^2.19.0" - doctrine "^3.0.0" - estree-to-babel "^3.1.0" - neo-async "^2.6.1" - node-dir "^0.1.10" - strip-indent "^3.0.0" - -react-dom@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - react-dom@18.1.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.1.0.tgz#7f6dd84b706408adde05e1df575b3a024d7e8a2f" @@ -30490,10 +27757,10 @@ react-fast-compare@2.0.4: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== -react-fast-compare@3.0.1, react-fast-compare@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.0.1.tgz#884d339ce1341aad22392e7a88664c71da48600e" - integrity sha512-C5vP0J644ofZGd54P8++O7AvrqMEbrGf8Ue0eAUJLJyw168dAX2aiYyX/zcY/eSNwO0IDjsKUaLE6n83D+TnEg== +react-fast-compare@^3.0.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49" + integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== react-focus-lock@^2.1.0: version "2.2.1" @@ -30542,7 +27809,17 @@ react-inspector@^4.0.0: prop-types "^15.6.1" storybook-chromatic "^2.2.2" -react-is@^16.12.0, react-is@^16.13.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.4, react-is@^16.9.0: +"react-instantsearch-core-v6@npm:react-instantsearch-core@6.40.4": + version "6.40.4" + resolved "https://registry.yarnpkg.com/react-instantsearch-core/-/react-instantsearch-core-6.40.4.tgz#74feaa94436a20df91febe64b7d8ef0f7b3e657a" + integrity sha512-sEOgRU2MKL8edO85sNHvKlZ5yq9OFw++CDsEqYpHJvbWLE/2J2N49XAUY90kior09I2kBkbgowBbov+Py1AubQ== + dependencies: + "@babel/runtime" "^7.1.2" + algoliasearch-helper "3.14.0" + prop-types "^15.6.2" + react-fast-compare "^3.0.0" + +react-is@^16.12.0, react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -30557,35 +27834,11 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -react-lazy-load@^3.0.13: - version "3.1.13" - resolved "https://registry.yarnpkg.com/react-lazy-load/-/react-lazy-load-3.1.13.tgz#236943f76b7084cc8458716d9632a1c9853ea5cd" - integrity sha512-eAVNUn3vhNj79Iv04NOCwy/sCLyqDEhL3j9aJKV7VJuRBDg6rCiB+BIWHuG7VXJGCgb//6nX/soR8PTyWRhFvQ== - dependencies: - eventlistener "0.0.1" - lodash.debounce "^4.0.0" - lodash.throttle "^4.0.0" - prop-types "^15.5.8" - -react-lifecycles-compat@^3.0.2, react-lifecycles-compat@^3.0.4: +react-lifecycles-compat@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== -react-native-animatable@^1.2.4: - version "1.3.3" - resolved "https://registry.yarnpkg.com/react-native-animatable/-/react-native-animatable-1.3.3.tgz#a13a4af8258e3bb14d0a9d839917e9bb9274ec8a" - integrity sha512-2ckIxZQAsvWn25Ho+DK3d1mXIgj7tITkrS4pYDvx96WyOttSvzzFeQnM2od0+FUMzILbdHDsDEqZvnz1DYNQ1w== - dependencies: - prop-types "^15.7.2" - -react-native-button@^2.3.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/react-native-button/-/react-native-button-2.4.0.tgz#42b487073a7ce7c54ab503f77c6ced1ab95742bf" - integrity sha512-4siaJlpOLeL9fAhX8VU3cnUfcGLe3E2zABDWSKxkF+NiYOd+AnKeYY29WXlV8hXhCFo+Ry7E+alrJ6zjZLTSfg== - dependencies: - prop-types "^15.5.10" - react-native-codegen@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/react-native-codegen/-/react-native-codegen-0.0.6.tgz#b3173faa879cf71bfade8d030f9c4698388f6909" @@ -30595,119 +27848,6 @@ react-native-codegen@^0.0.6: jscodeshift "^0.11.0" nullthrows "^1.1.1" -react-native-gesture-handler@1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/react-native-gesture-handler/-/react-native-gesture-handler-1.6.1.tgz#678e2dce250ed66e93af409759be22cd6375dd17" - integrity sha512-gQgIKhDiYf754yzhhliagLuLupvGb6ZyBdzYzr7aus3Fyi87TLOw63ers+r4kGw0h26oAWTAdHd34JnF4NeL6Q== - dependencies: - "@egjs/hammerjs" "^2.0.17" - hoist-non-react-statics "^2.3.1" - invariant "^2.2.4" - prop-types "^15.7.2" - -react-native-iphone-x-helper@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz#20c603e9a0e765fd6f97396638bdeb0e5a60b010" - integrity sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg== - -react-native-modal-dropdown@0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/react-native-modal-dropdown/-/react-native-modal-dropdown-0.7.0.tgz#d030c4159ff026bedd5c20aa59b146495b860814" - integrity sha512-h2UrozBByQhL56XDboj/wjc/5Ny787eLQ++4ql7TecBdbLqbf+tlE62VeXKz30XVMN3iUVYUR/XmM/RIwLIXEg== - dependencies: - deprecated-react-native-listview "0.0.5" - prop-types "^15.6.0" - -react-native-reanimated@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/react-native-reanimated/-/react-native-reanimated-1.7.0.tgz#896db2576552ac59d288a1f6c7f00afc171f240c" - integrity sha512-FQWSqP605eQVJumuK2HpR+7heF0ZI+qfy4jNguv3Xv8nPFHeIgZaRTXHCEQL2AcuSIj50zy8jGJf5l134QMQWQ== - -react-native-router-flux@4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/react-native-router-flux/-/react-native-router-flux-4.2.0.tgz#71c59f6a6250e9ed10d61ade506b9b809f879db0" - integrity sha512-ab6HZNKNfYhbk/UEiwSGOY6/lhikybOIGjL8CV9bQSLn2sNT1hkAJ1tRReQQVxHlgNI7N4oWfuH1ewk9rePsRA== - dependencies: - "@babel/runtime" "^7.6.0" - add "^2.0.6" - lodash "^4.17.15" - opencollective "^1.0.3" - path-to-regexp "^2.4.0" - prop-types "^15.6.2" - react-navigation "^4.x" - react-navigation-drawer "^2.2.1" - react-navigation-stack "^1.7.3" - react-navigation-tabs "^2.5.2" - remove "^0.1.5" - -react-native-safe-area-view@^0.14.9: - version "0.14.9" - resolved "https://registry.yarnpkg.com/react-native-safe-area-view/-/react-native-safe-area-view-0.14.9.tgz#90ee8383037010d9a5055a97cf97e4c1da1f0c3d" - integrity sha512-WII/ulhpVyL/qbYb7vydq7dJAfZRBcEhg4/UWt6F6nAKpLa3gAceMOxBxI914ppwSP/TdUsandFy6lkJQE0z4A== - dependencies: - hoist-non-react-statics "^2.3.1" - -react-native-screens@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/react-native-screens/-/react-native-screens-2.2.0.tgz#cc4cdf17426fdda97ad93a5e812a1899390f1978" - integrity sha512-a0VzxOWot7F9B/GQyDSssBRd3jUJazFnTQS61IiyReWB6aHlFhf3Xz10jBRoURXy1EMCDCHgenmTVTkKHpKyqQ== - dependencies: - debounce "^1.2.0" - -react-native-star-rating@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-native-star-rating/-/react-native-star-rating-1.1.0.tgz#57fcd023c63e947427c4dbbd1c8f4cc49e5c48ce" - integrity sha512-ocOYx+BKUvfruvXm45MBbQZtpkVO3PQieBDepB0FaLuxE3vUtDTPzHqXuBes3iCM5oRi5umrnmMUMsM0mEq5ZA== - dependencies: - prop-types "^15.5.10" - react-native-animatable "^1.2.4" - react-native-button "^2.3.0" - react-native-vector-icons "^4.5.0" - -react-native-tab-view@^2.15.2: - version "2.16.0" - resolved "https://registry.yarnpkg.com/react-native-tab-view/-/react-native-tab-view-2.16.0.tgz#cae72c7084394bd328fac5fefb86cd966df37a86" - integrity sha512-ac2DmT7+l13wzIFqtbfXn4wwfgtPoKzWjjZyrK1t+T8sdemuUvD4zIt+UImg03fu3s3VD8Wh/fBrIdcqQyZJWg== - -react-native-vector-icons@6.6.0: - version "6.6.0" - resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-6.6.0.tgz#66cf004918eb05d90778d64bd42077c1800d481b" - integrity sha512-MImKVx8JEvVVBnaShMr7/yTX4Y062JZMupht1T+IEgbqBj4aQeQ1z2SH4VHWKNtWtppk4kz9gYyUiMWqx6tNSw== - dependencies: - lodash "^4.0.0" - prop-types "^15.6.2" - yargs "^13.2.2" - -react-native-vector-icons@^4.5.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/react-native-vector-icons/-/react-native-vector-icons-4.6.0.tgz#e4014311ffa6de397d914ffc31b7097a874cc8d5" - integrity sha512-rpfhfPiXCK2PX1nrNhdxSMrEGB/Gw/SvKoPM0G2wAkSoqynnes19K0VYI+Up7DqR1rFIpE4hP2erpT1tNx2tfg== - dependencies: - lodash "^4.0.0" - prop-types "^15.5.10" - yargs "^8.0.2" - -react-native-view-shot@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/react-native-view-shot/-/react-native-view-shot-3.1.2.tgz#8c8e84c67a4bc8b603e697dbbd59dbc9b4f84825" - integrity sha512-9u9fPtp6a52UMoZ/UCPrCjKZk8tnkI9To0Eh6yYnLKFEGkRZ7Chm6DqwDJbYJHeZrheCCopaD5oEOnRqhF4L2Q== - -react-native-web@0.11.7, react-native-web@~0.11.7: - version "0.11.7" - resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.11.7.tgz#d173d5a9b58db23b6d442c4bc4c81e9939adac23" - integrity sha512-w1KAxX2FYLS2GAi3w3BnEZg/IUu7FdgHnLmFKHplRnHMV3u1OPB2EVA7ndNdfu7ds4Rn2OZjSXoNh6F61g3gkA== - dependencies: - array-find-index "^1.0.2" - create-react-class "^15.6.2" - debounce "^1.2.0" - deep-assign "^3.0.0" - fbjs "^1.0.0" - hyphenate-style-name "^1.0.2" - inline-style-prefixer "^5.0.3" - normalize-css-color "^1.0.2" - prop-types "^15.6.0" - react-timer-mixin "^0.13.4" - react-native-web@0.17.1: version "0.17.1" resolved "https://registry.yarnpkg.com/react-native-web/-/react-native-web-0.17.1.tgz#90d473c89dd99b88bc9830b2a9fcdd2fc5f04902" @@ -30759,70 +27899,6 @@ react-native@0.64.3: whatwg-fetch "^3.0.0" ws "^6.1.4" -"react-native@https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz": - version "0.61.4" - resolved "https://github.com/expo/react-native/archive/sdk-37.0.1.tar.gz#69f3f63c36c9df52611847a67c9d94596c1754cc" - dependencies: - "@babel/runtime" "^7.0.0" - "@react-native-community/cli" "^3.0.0-alpha.1" - "@react-native-community/cli-platform-android" "^3.0.0-alpha.1" - "@react-native-community/cli-platform-ios" "^3.0.0-alpha.1" - abort-controller "^3.0.0" - art "^0.10.0" - base64-js "^1.1.2" - connect "^3.6.5" - create-react-class "^15.6.3" - escape-string-regexp "^1.0.5" - event-target-shim "^5.0.1" - fbjs "^1.0.0" - fbjs-scripts "^1.1.0" - hermes-engine "^0.2.1" - invariant "^2.2.4" - jsc-android "^245459.0.0" - metro-babel-register "^0.56.0" - metro-react-native-babel-transformer "^0.56.0" - metro-source-map "^0.56.0" - nullthrows "^1.1.0" - pretty-format "^24.7.0" - promise "^7.1.1" - prop-types "^15.7.2" - react-devtools-core "^3.6.3" - react-refresh "^0.4.0" - regenerator-runtime "^0.13.2" - scheduler "0.15.0" - stacktrace-parser "^0.1.3" - whatwg-fetch "^3.0.0" - -react-navigation-drawer@^2.2.1: - version "2.7.1" - resolved "https://registry.yarnpkg.com/react-navigation-drawer/-/react-navigation-drawer-2.7.1.tgz#b025be11f612e8215f15f9f605851d281606fe82" - integrity sha512-W36XDl+Ts5uGNr6Ryt1xGrQ5JTeddPmvR31bNX7o6Oo7OsdPZ3b1+oMDoRClGca0d6Ggo7btIqiWUsUshm+p/g== - -react-navigation-stack@^1.7.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/react-navigation-stack/-/react-navigation-stack-1.10.3.tgz#e714e442b20427f0d2d3c18fce1f9e8cfe69be0b" - integrity sha512-1gksFi/g/Lg9sBhgLlD0OiEB5xnatHb4C0eNMA5tli9cTVlhq375XNPIqOiTyftibBmjdApAsZFj5srUCoOu/w== - dependencies: - prop-types "^15.7.2" - -react-navigation-tabs@^2.5.2: - version "2.11.1" - resolved "https://registry.yarnpkg.com/react-navigation-tabs/-/react-navigation-tabs-2.11.1.tgz#dd2ccb04c540b4439aadc4bc8f5a776dfc90439f" - integrity sha512-wq2wR3awu6PKimmVOycBf+iTPA9FWThbJwcaDBQEhQiiviXQzAtT3lw3nV9oqNIg4v65tdPhL1Dg8ptTJ03NjQ== - dependencies: - hoist-non-react-statics "^3.3.2" - react-lifecycles-compat "^3.0.4" - react-native-iphone-x-helper "^1.3.0" - react-native-tab-view "^2.15.2" - -react-navigation@^4.x: - version "4.4.4" - resolved "https://registry.yarnpkg.com/react-navigation/-/react-navigation-4.4.4.tgz#8cda2219196311db440e54998bc724523359949f" - integrity sha512-08Nzy1aKEd73496CsuzN49vLFmxPKYF5WpKGgGvkQ10clB79IRM2BtAfVl6NgPKuUM8FXq1wCsrjo/c5ftl5og== - dependencies: - "@react-navigation/core" "^3.7.9" - "@react-navigation/native" "^3.8.4" - react-popper-tooltip@^2.8.3: version "2.11.1" resolved "https://registry.yarnpkg.com/react-popper-tooltip/-/react-popper-tooltip-2.11.1.tgz#3c4bdfd8bc10d1c2b9a162e859bab8958f5b2644" @@ -30866,48 +27942,6 @@ react-refresh@^0.9.0: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf" integrity sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ== -react-router-dom@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.2.0.tgz#9e65a4d0c45e13289e66c7b17c7e175d0ea15662" - integrity sha512-gxAmfylo2QUjcwxI63RhQ5G85Qqt4voZpUXSEqCwykV0baaOTQDR1f0PmY8AELqIyVc0NEZUj0Gov5lNGcXgsA== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.2.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - -react-router@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-3.2.1.tgz#b9a3279962bdfbe684c8bd0482b81ef288f0f244" - integrity sha512-SXkhC0nr3G0ltzVU07IN8jYl0bB6FsrDIqlLC9dK3SITXqyTJyM7yhXlUqs89w3Nqi5OkXsfRUeHX+P874HQrg== - dependencies: - create-react-class "^15.5.1" - history "^3.0.0" - hoist-non-react-statics "^2.3.1" - invariant "^2.2.1" - loose-envify "^1.2.0" - prop-types "^15.5.6" - warning "^3.0.0" - -react-router@5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.0.tgz#424e75641ca8747fbf76e5ecca69781aa37ea293" - integrity sha512-smz1DUuFHRKdcJC0jobGo8cVbhO3x50tCL4icacOlcwDOEQPq4TMqwx3sY1TP+DvtTgz4nm3thuo7A+BK2U0Dw== - dependencies: - "@babel/runtime" "^7.1.2" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - react-select@^3.0.8, react-select@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.2.0.tgz#de9284700196f5f9b5277c5d850a9ce85f5c72fe" @@ -30940,17 +27974,6 @@ react-sizeme@^2.5.2, react-sizeme@^2.6.7: shallowequal "^1.1.0" throttle-debounce "^2.1.0" -react-slick@~0.25.2: - version "0.25.2" - resolved "https://registry.yarnpkg.com/react-slick/-/react-slick-0.25.2.tgz#56331b67d47d8bcfe2dceb6acab1c8fd5bd1f6bc" - integrity sha512-8MNH/NFX/R7zF6W/w+FS5VXNyDusF+XDW1OU0SzODEU7wqYB+ZTGAiNJ++zVNAVqCAHdyCybScaUB+FCZOmBBw== - dependencies: - classnames "^2.2.5" - enquire.js "^2.1.6" - json2mq "^0.2.0" - lodash.debounce "^4.0.8" - resize-observer-polyfill "^1.5.0" - react-syntax-highlighter@^11.0.2: version "11.0.2" resolved "https://registry.yarnpkg.com/react-syntax-highlighter/-/react-syntax-highlighter-11.0.2.tgz#4e3f376e752b20d2f54e4c55652fd663149e4029" @@ -30962,16 +27985,6 @@ react-syntax-highlighter@^11.0.2: prismjs "^1.8.4" refractor "^2.4.1" -react-test-renderer@17.0.2, react-test-renderer@^17.0.0: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c" - integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ== - dependencies: - object-assign "^4.1.1" - react-is "^17.0.2" - react-shallow-renderer "^16.13.1" - scheduler "^0.20.2" - react-test-renderer@18.1.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-18.1.0.tgz#35b75754834cf9ab517b6813db94aee0a6b545c3" @@ -30981,15 +27994,15 @@ react-test-renderer@18.1.0: react-shallow-renderer "^16.15.0" scheduler "^0.22.0" -react-test-renderer@~16.9.0: - version "16.9.0" - resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-16.9.0.tgz#7ed657a374af47af88f66f33a3ef99c9610c8ae9" - integrity sha512-R62stB73qZyhrJo7wmCW9jgl/07ai+YzvouvCXIJLBkRlRqLx4j9RqcLEAfNfU3OxTGucqR2Whmn3/Aad6L3hQ== +react-test-renderer@^17.0.0: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-17.0.2.tgz#4cd4ae5ef1ad5670fc0ef776e8cc7e1231d9866c" + integrity sha512-yaQ9cB89c17PUb0x6UfWRs7kQCorVdHlutU1boVPEsB8IDZH6n9tHxMacc3y0JoXOJUsZb/t/Mb8FUWMKaM7iQ== dependencies: object-assign "^4.1.1" - prop-types "^15.6.2" - react-is "^16.9.0" - scheduler "^0.15.0" + react-is "^17.0.2" + react-shallow-renderer "^16.13.1" + scheduler "^0.20.2" react-textarea-autosize@^7.1.0: version "7.1.2" @@ -30999,18 +28012,6 @@ react-textarea-autosize@^7.1.0: "@babel/runtime" "^7.1.2" prop-types "^15.6.0" -react-themeable@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/react-themeable/-/react-themeable-1.1.0.tgz#7d4466dd9b2b5fa75058727825e9f152ba379a0e" - integrity sha1-fURm3ZsrX6dQWHJ4JenxUro3mg4= - dependencies: - object-assign "^3.0.0" - -react-timer-mixin@^0.13.4: - version "0.13.4" - resolved "https://registry.yarnpkg.com/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz#75a00c3c94c13abe29b43d63b4c65a88fc8264d3" - integrity sha512-4+ow23tp/Tv7hBM5Az5/Be/eKKF7DIvJ09voz5LyHGQaqqz9WV8YMs31eFvcYQs7d451LSg7kDJV70XYN/Ug/Q== - react-transition-group@^4.3.0: version "4.4.2" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" @@ -31029,14 +28030,6 @@ react@17.0.1: loose-envify "^1.1.0" object-assign "^4.1.1" -react@17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - react@18.1.0: version "18.1.0" resolved "https://registry.yarnpkg.com/react/-/react-18.1.0.tgz#6f8620382decb17fdc5cc223a115e2adbf104890" @@ -31120,14 +28113,6 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" -read-pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" - integrity sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4= - dependencies: - find-up "^2.0.0" - read-pkg "^2.0.0" - read-pkg-up@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" @@ -31162,15 +28147,6 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read-pkg@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" - integrity sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg= - dependencies: - load-json-file "^2.0.0" - normalize-package-data "^2.3.2" - path-type "^2.0.0" - read-pkg@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" @@ -31415,11 +28391,6 @@ regenerate@^1.4.2: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== -regenerator-runtime@^0.10.0: - version "0.10.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" - integrity sha512-02YopEIhAgiBHWeoTiA8aitHDt8z6w+rQqNuIftlM+ZtvSl/brTouaU7DW6GO/cHtvxJvS4Hwv2ibKdxIRi24w== - regenerator-runtime@^0.11.0: version "0.11.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" @@ -31675,13 +28646,6 @@ remove-trailing-slash@^0.1.0: resolved "https://registry.yarnpkg.com/remove-trailing-slash/-/remove-trailing-slash-0.1.1.tgz#be2285a59f39c74d1bce4f825950061915e3780d" integrity sha512-o4S4Qh6L2jpnCy83ysZDau+VORNvnFw07CKSAymkd6ICNVEPisMyzlc00KlvvicsxKck94SEwhDnMNdICzO+tA== -remove@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/remove/-/remove-0.1.5.tgz#095ffd827d65c9f41ad97d33e416a75811079955" - integrity sha1-CV/9gn1lyfQa2X0z5BanWBEHmVU= - dependencies: - seq ">= 0.3.5" - renderkid@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" @@ -31844,7 +28808,7 @@ reselect@^4.0.0: resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== -resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: +resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== @@ -31891,11 +28855,6 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" @@ -31920,7 +28879,7 @@ resolve@^1.1.3, resolve@^1.1.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.3.2, resolve@^1.4.0: version "1.22.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -32129,14 +29088,6 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -rmc-feedback@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/rmc-feedback/-/rmc-feedback-2.0.0.tgz#cbc6cb3ae63c7a635eef0e25e4fbaf5ac366eeaa" - integrity sha512-5PWOGOW7VXks/l3JzlOU9NIxRpuaSS8d9zA3UULUCuTKnpwBHNvv1jSJzxgbbCQeYzROWUpgKI4za3X4C/mKmQ== - dependencies: - babel-runtime "6.x" - classnames "^2.2.5" - roarr@^2.15.3: version "2.15.4" resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" @@ -32380,30 +29331,6 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rx-lite-aggregates@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" - integrity sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74= - dependencies: - rx-lite "*" - -rx-lite@*, rx-lite@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" - integrity sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ= - -rx@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" - integrity sha1-pfE/957zt0D+MKqAP7CfmIBdR4I= - -rxjs@^5.4.3: - version "5.5.12" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.5.12.tgz#6fa61b8a77c3d793dbaf270bee2f43f652d741cc" - integrity sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw== - dependencies: - symbol-observable "1.0.1" - rxjs@^6.4.0, rxjs@^6.5.3, rxjs@^6.6.0, rxjs@^6.6.6: version "6.6.7" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" @@ -32544,14 +29471,6 @@ saxes@^5.0.1: dependencies: xmlchars "^2.2.0" -scheduler@0.15.0, scheduler@^0.15.0: - version "0.15.0" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.15.0.tgz#6bfcf80ff850b280fed4aeecc6513bc0b4f17f8e" - integrity sha512-xAefmSfN6jqAa7Kuq7LIJY0bwAPG3xlCj0HMEBQk1lxYiDKZscY2xJ5U/61ZTrYbmNQbXa+gc7czPkVo11tnCg== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler@^0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.19.1.tgz#4f3e2ed2c1a7d65681f4c854fa8c5a1ccb40f196" @@ -32602,7 +29521,7 @@ schema-utils@^3.0.0, schema-utils@^3.1.1: ajv "^6.12.5" ajv-keywords "^3.5.2" -scriptjs@2.5.9, scriptjs@^2.5.8: +scriptjs@2.5.9: version "2.5.9" resolved "https://registry.yarnpkg.com/scriptjs/-/scriptjs-2.5.9.tgz#343915cd2ec2ed9bfdde2b9875cd28f59394b35f" integrity sha512-qGVDoreyYiP1pkQnbnFAUIS5AjenNwwQBdl7zeos9etl+hYKWahjRTfzAZZYBv5xNHx7vNKCmaLDQZ6Fr2AEXg== @@ -32617,11 +29536,6 @@ search-insights@^2.6.0: resolved "https://registry.yarnpkg.com/search-insights/-/search-insights-2.6.0.tgz#bb8771a73b83c4a0f1f207c2f64fea01acd3e7d0" integrity sha512-vU2/fJ+h/Mkm/DJOe+EaM5cafJv/1rRTZpGJTuFPf/Q5LjzgMDsqPdSaZsAe+GAWHHsfsu+rQSAn6c8IGtBEVw== -section-iterator@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a" - integrity sha1-v0RNev7rlK1Dw5rS+yYVFifMuio= - section-matter@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" @@ -32798,14 +29712,6 @@ sentence-case@^3.0.3: tslib "^2.0.3" upper-case-first "^2.0.2" -"seq@>= 0.3.5": - version "0.3.5" - resolved "https://registry.yarnpkg.com/seq/-/seq-0.3.5.tgz#ae02af3a424793d8ccbf212d69174e0c54dffe38" - integrity sha1-rgKvOkJHk9jMvyEtaRdODFTf/jg= - dependencies: - chainsaw ">=0.0.7 <0.1" - hashish ">=0.0.2 <0.1" - serialize-error@6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-6.0.0.tgz#ccfb887a1dd1c48d6d52d7863b92544331fd752b" @@ -32989,16 +29895,6 @@ sha.js@^2.4.0, sha.js@^2.4.8, sha.js@~2.4.4: inherits "^2.0.1" safe-buffer "^5.0.1" -shallow-clone@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" - integrity sha1-WQnodLp3EG1zrEFM/sH/yofZcGA= - dependencies: - is-extendable "^0.1.1" - kind-of "^2.0.1" - lazy-cache "^0.2.3" - mixin-object "^2.0.1" - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -33006,12 +29902,12 @@ shallow-clone@^3.0.0: dependencies: kind-of "^6.0.2" -shallow-equal@^1.0.0, shallow-equal@^1.1.0: +shallow-equal@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.0.tgz#fd828d2029ff4e19569db7e19e535e94e2d1f5cc" integrity sha512-Z21pVxR4cXsfwpMKMhCEIO1PCi5sp7KEp+CmOpBQ+E8GpHwKOw2sEzk7sgblM3d/j4z4gakoWEoPcjK0VJQogA== -shallowequal@1.1.0, shallowequal@^1.0.1, shallowequal@^1.0.2, shallowequal@^1.1.0: +shallowequal@1.1.0, shallowequal@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8" integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ== @@ -33084,11 +29980,6 @@ shelljs@0.8.5, shelljs@^0.8.3, shelljs@^0.8.4: interpret "^1.0.0" rechoir "^0.6.2" -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - shiki@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.11.1.tgz#df0f719e7ab592c484d8b73ec10e215a503ab8cc" @@ -33273,11 +30164,6 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - slugify@^1.3.4: version "1.6.5" resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.6.5.tgz#c8f5c072bf2135b80703589b39a3d41451fbe8c8" @@ -33561,11 +30447,6 @@ speedometer@~1.0.0: resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.0.0.tgz#cd671cb06752c22bca3370e2f334440be4fc62e2" integrity sha1-zWccsGdSwivKM3Di8zREC+T8YuI= -split-on-first@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f" - integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw== - split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -33919,21 +30800,11 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= -strict-uri-encode@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546" - integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY= - string-argv@~0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== -string-convert@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97" - integrity sha1-aYLMMEn7tM2F+LJFaLnZvznu/5c= - string-hash@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" @@ -33947,14 +30818,6 @@ string-length@^2.0.0: astral-regex "^1.0.0" strip-ansi "^4.0.0" -string-length@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837" - integrity sha512-Ttp5YvkGm5v9Ijagtaz1BnN+k9ObpvS0eIBblPMp2YWL8FBmi9qblQ9fexc2k/CXFgrTIteU3jAw3payCnwSTA== - dependencies: - astral-regex "^1.0.0" - strip-ansi "^5.2.0" - string-length@^4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" @@ -34267,11 +31130,6 @@ styled-jsx@5.0.2: resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.2.tgz#ff230fd593b737e9e68b630a694d460425478729" integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ== -styled-jsx@5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.7.tgz#be44afc53771b983769ac654d355ca8d019dff48" - integrity sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA== - stylehacks@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-4.0.3.tgz#6718fcaf4d1e07d8a1318690881e8d96726a71d5" @@ -34533,17 +31391,12 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -svg-parser@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/svg-parser/-/svg-parser-2.0.4.tgz#fdc2e29e13951736140b76cb122c8ee6630eb6b5" - integrity sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ== - svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== -svgo@^1.0.0, svgo@^1.2.2: +svgo@^1.0.0: version "1.3.2" resolved "https://registry.yarnpkg.com/svgo/-/svgo-1.3.2.tgz#b6dc511c063346c9e415b81e43401145b96d4167" integrity sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw== @@ -34583,11 +31436,6 @@ swap-case@^1.1.0: lower-case "^1.1.1" upper-case "^1.1.1" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= - symbol-observable@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" @@ -35011,11 +31859,6 @@ thread-loader@^3.0.4: neo-async "^2.6.2" schema-utils "^3.0.0" -throat@^4.0.0, throat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -35074,11 +31917,6 @@ time-fix-plugin@^2.0.7: resolved "https://registry.yarnpkg.com/time-fix-plugin/-/time-fix-plugin-2.0.7.tgz#4ba70ae2e40cedf34dabe505eda7b71b1b244f50" integrity sha512-uVFet1LQToeUX0rTcSiYVYVoGuBpc8gP/2jnlUzuHMHe+gux6XLsNzxLUweabMwiUj5ejhoIMsUI55nVSEa/Vw== -time-stamp@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" - integrity sha1-dkpaEa9QVhkhsTPztE5hhofg9cM= - timed-out@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -35116,21 +31954,6 @@ tiny-glob@^0.2.9: globalyzer "0.1.0" globrex "^0.1.2" -tiny-invariant@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.1.0.tgz#634c5f8efdc27714b7f386c35e6760991d230875" - integrity sha512-ytxQvrb1cPc9WBEI/HSeYYoGD0kWnGEOR8RY6KomWLBVhqz0RgTwVO9dLrGz7dC+nN9llyI7OKAgRq8Vq4ZBSw== - -tiny-queue@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" - integrity sha1-JaZ/LG4lOyypQZd7XvdELvl6YEY= - -tiny-warning@^1.0.0, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - tinycolor2@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" @@ -35308,16 +32131,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -traverse@>=0.2.4, traverse@^0.6.6, traverse@~0.6.6: +traverse@^0.6.6, traverse@~0.6.6: version "0.6.6" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.6.tgz#cbdf560fd7b9af632502fed40f918c157ea97137" integrity sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc= -"traverse@>=0.3.0 <0.4": - version "0.3.9" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" - integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= - tree-kill@1.2.2, tree-kill@^1.1.0: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -35643,11 +32461,6 @@ typescript@*, typescript@5.1.3: resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz#8d84219244a6b40b6fb2b33cc1c062f715b9e826" integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== -typescript@3.7.3: - version "3.7.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.3.tgz#b36840668a16458a7025b9eabfad11b66ab85c69" - integrity sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw== - "typescript@^3 || ^4": version "4.9.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" @@ -35673,7 +32486,7 @@ typical@^6.0.1: resolved "https://registry.yarnpkg.com/typical/-/typical-6.0.1.tgz#89bd1a6aa5e5e96fa907fb6b7579223bff558a06" integrity sha512-+g3NEp7fJLe9DPa1TArHm9QAA7YciZmWnfAqEaFrBihQ7epOv9i99rjtgb6Iz0wh3WuQDjsCTDfgRoGnmHN81A== -ua-parser-js@^0.7.18, ua-parser-js@^0.7.28, ua-parser-js@^0.7.30: +ua-parser-js@^0.7.28, ua-parser-js@^0.7.30: version "0.7.32" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.32.tgz#cd8c639cdca949e30fa68c44b7813ef13e36d211" integrity sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw== @@ -35846,61 +32659,6 @@ unified@^6.1.6: vfile "^2.0.0" x-is-string "^0.1.0" -unimodules-app-loader@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unimodules-app-loader/-/unimodules-app-loader-1.0.2.tgz#0af821db8ae5d7c09d2be3c62ca5aab571d6e9ac" - integrity sha512-ryRAqSndIkCnWAr5jzSL6yjOrCBeIihItELUTykzi4ZxYV9j4Yl0Sd5+VKl1v/UvB6UNdgIGY4oU7S1b173/FA== - -unimodules-barcode-scanner-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-barcode-scanner-interface/-/unimodules-barcode-scanner-interface-5.1.0.tgz#6d24322b6db556b21eca99a130673c7e07d86559" - integrity sha512-FUau0mm4sBOGmlekltY0iAimJ438w3rtWiv6hcjE77Map527aCH3GyjnZSw78raVxe598EXhWHviuwRxOGINYg== - -unimodules-camera-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-camera-interface/-/unimodules-camera-interface-5.1.0.tgz#ea43a8d05b7b1a9053e6b2281b428a1e80853661" - integrity sha512-uwBmZ3XS6vkdzRAmiDhUE/P7fafN7ufXoRuBDGoX/Q9kIiKg61D8HzTmhLMelvJFW6eCjoBJfh/zRyZ54qcjGg== - -unimodules-constants-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-constants-interface/-/unimodules-constants-interface-5.1.0.tgz#916a8203a887b53cdbcd80b63bc6fd56c85ccfd2" - integrity sha512-TlrqwtKt2G0QH4Fn1ko3tRtLX+eUGSnCBuu1TiAGlsQ5FM/1+AGuJNftHdUwZY1DncIAlw6lhNW+amv0hw5ocg== - -unimodules-face-detector-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-face-detector-interface/-/unimodules-face-detector-interface-5.1.0.tgz#56b4e8c238d8b38f7937f2eb87212d5f87c463f9" - integrity sha512-0qDA6j1WvPM98q32aKvRdFhgSa9Nu8lqNUlrgE740UTYsAmfQl8lM/r2TOuR1k3dVC14q33YvLizSOYM5FLhAw== - -unimodules-file-system-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-file-system-interface/-/unimodules-file-system-interface-5.1.0.tgz#adcba6d6dbb58d889175425dedcbb1501f498ab7" - integrity sha512-G2QXhEXY3uHuDD50MWI7C/nesbVlf2C0QHTs+fAt1VpmWYWfdDaeqgO67f/QRz8FH8xm3ul9XvgP6nA+P0xfIg== - -unimodules-font-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-font-interface/-/unimodules-font-interface-5.1.0.tgz#953c1eb6e1f221f0c7d427d7aba78cce599b4b27" - integrity sha512-ZKycNecNN0xxGIo9Db2n8RYU+ijlc+hzpE5acVSiIlmMjTsiOODRLkF++yKsZxglGXn/blgtBLrcTQr4jJV4MQ== - -unimodules-image-loader-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-image-loader-interface/-/unimodules-image-loader-interface-5.1.0.tgz#40eeecb1d9409b51595b559023230ce50485b626" - integrity sha512-yU1OPWMtZ9QcW5CxLE1DYWrpJGZ1hRGdoFG3vyk4syUS8QsCPR0HXqcI6KlTpI6wcLA0+HtS+1CmgJCMCUDd4w== - -unimodules-permissions-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-permissions-interface/-/unimodules-permissions-interface-5.1.0.tgz#146062ee5cde1f00f34ba2692efab5f0c6f55d02" - integrity sha512-3Mz9A4a+iYF57ZeE99nidRPNM7dX3dzTZRvRQyCP5+CvsEmGNlLTIbTQ7fxKECoe3I6cjw94gNSirxIbwb3lDg== - -unimodules-sensors-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-sensors-interface/-/unimodules-sensors-interface-5.1.0.tgz#2d8f5f15a8b00b3f0aab59c3ff474f39735d634f" - integrity sha512-v8nRFRHtl4jFI1aiAmWurPKDuvboSxj0qoqpy/IB3xkkzBfw4KsZQ1b1yomwNbv9cCqIkFxaNAOzyrvVZrz/dA== - -unimodules-task-manager-interface@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unimodules-task-manager-interface/-/unimodules-task-manager-interface-5.1.0.tgz#49fe4431464faa576ba3453a1824030debbf8d35" - integrity sha512-t7FSWOdw4ev9SlqPzfw9rOKlFyryZbrcmjEr0n6HtPXqZ4NRfPqXtYSjoVWswGb3iGr3GPOIHZ/OQ6Z6StL1NA== - union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4" @@ -36327,7 +33085,7 @@ use-subscription@^1.0.0: dependencies: object-assign "^4.1.1" -use-sync-external-store@1.2.0, use-sync-external-store@^1.0.0: +use-sync-external-store@^1.0.0: version "1.2.0" resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== @@ -36438,7 +33196,7 @@ v8-compile-cache@2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe" integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w== -v8-compile-cache@2.3.0, v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3, v8-compile-cache@^2.1.1, v8-compile-cache@^2.3.0: +v8-compile-cache@2.3.0, v8-compile-cache@^2.0.0, v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== @@ -36452,15 +33210,6 @@ v8-to-istanbul@^8.1.0: convert-source-map "^1.6.0" source-map "^0.7.3" -v8-to-istanbul@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.0.1.tgz#b6f994b0b5d4ef255e17a0d17dc444a9f5132fa4" - integrity sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w== - dependencies: - "@jridgewell/trace-mapping" "^0.3.12" - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - valid-url@~1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" @@ -36503,11 +33252,6 @@ validator@^8.0.0: resolved "https://registry.yarnpkg.com/validator/-/validator-8.2.0.tgz#3c1237290e37092355344fef78c231249dab77b9" integrity sha512-Yw5wW34fSv5spzTXNkokD6S6/Oq92d8q/t14TqsS3fAiA1RYnxSFSIZ+CY3n6PGGRCq5HhJTSepQvFUS2QUDxA== -value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - vary@^1.1.2, vary@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" @@ -36953,20 +33697,13 @@ ware@^1.3.0: dependencies: wrap-fn "^0.1.0" -warning@4.x, warning@^4.0.1, warning@^4.0.2, warning@^4.0.3, warning@~4.0.3: +warning@^4.0.2, warning@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== dependencies: loose-envify "^1.0.0" -warning@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/warning/-/warning-3.0.0.tgz#32e5377cb572de4ab04753bdf8821c01ed605b7c" - integrity sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w= - dependencies: - loose-envify "^1.0.0" - watchpack-chokidar2@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" @@ -37159,23 +33896,6 @@ webpack-cli@3.3.7: v8-compile-cache "2.0.3" yargs "13.2.4" -webpack-cli@^3.3.7: - version "3.3.12" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.12.tgz#94e9ada081453cd0aa609c99e500012fd3ad2d4a" - integrity sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag== - dependencies: - chalk "^2.4.2" - cross-spawn "^6.0.5" - enhanced-resolve "^4.1.1" - findup-sync "^3.0.0" - global-modules "^2.0.0" - import-local "^2.0.0" - interpret "^1.4.0" - loader-utils "^1.4.0" - supports-color "^6.1.0" - v8-compile-cache "^2.1.1" - yargs "^13.3.2" - webpack-dev-middleware@^3.4.0, webpack-dev-middleware@^3.7.0, webpack-dev-middleware@^3.7.2: version "3.7.3" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.3.tgz#0639372b143262e2b84ab95d3b91a7597061c2c5" @@ -37336,7 +34056,7 @@ webpack-virtual-modules@^0.2.0: dependencies: debug "^3.0.0" -webpack@4.41.5, webpack@4.43.0, webpack@4.46.0, webpack@^4.0.0, webpack@^4.33.0, webpack@^4.38.0, webpack@^4.41.5, webpack@^4.46.0: +webpack@4.41.5, webpack@4.43.0, webpack@4.46.0, webpack@^4.0.0, webpack@^4.33.0, webpack@^4.38.0, webpack@^4.46.0: version "4.46.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== @@ -37502,7 +34222,7 @@ which-pm@2.0.0: load-yaml-file "^0.2.0" path-exists "^4.0.0" -which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1: +which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -37688,15 +34408,6 @@ write-file-atomic@2.4.1: imurmurhash "^0.1.4" signal-exit "^3.0.2" -write-file-atomic@^1.2.0: - version "1.3.4" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.4.tgz#f807a4f0b1d9e913ae7a48112e6cc3af1991b45f" - integrity sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8= - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - slide "^1.1.5" - write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: version "2.4.3" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" @@ -37784,7 +34495,7 @@ ws@^1.1.0, ws@^1.1.5: options ">=0.0.5" ultron "1.0.x" -ws@^3.0.0, ws@^3.3.1: +ws@^3.0.0: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== @@ -37918,7 +34629,7 @@ xml-name-validator@^4.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== -xml2js@0.4.23, xml2js@^0.4.23: +xml2js@0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -37973,11 +34684,6 @@ xmldoc@^1.1.2: dependencies: sax "^1.2.1" -xpipe@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/xpipe/-/xpipe-1.0.5.tgz#8dd8bf45fc3f7f55f0e054b878f43a62614dafdf" - integrity sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98= - "xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -38000,7 +34706,7 @@ y18n@^3.2.1: resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= -"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0: +y18n@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== @@ -38040,7 +34746,7 @@ yargs-parser@20.2.4: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^20.2.9: +yargs-parser@20.x, yargs-parser@^20.2.2, yargs-parser@^20.2.3: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== @@ -38050,14 +34756,6 @@ yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.1: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs-parser@^11.1.1: - version "11.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4" - integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - yargs-parser@^13.1.0, yargs-parser@^13.1.2: version "13.1.2" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" @@ -38081,13 +34779,6 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" -yargs-parser@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-7.0.0.tgz#8d0ac42f16ea55debd332caf4c4038b3e3f5dfd9" - integrity sha1-jQrELxbqVd69MyyvTEA4s+P139k= - dependencies: - camelcase "^4.1.0" - yargs@13.2.4: version "13.2.4" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83" @@ -38124,25 +34815,7 @@ yargs@6.6.0: y18n "^3.2.1" yargs-parser "^4.2.0" -yargs@^12.0.5: - version "12.0.5" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13" - integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw== - dependencies: - cliui "^4.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^1.0.1" - os-locale "^3.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1 || ^4.0.0" - yargs-parser "^11.1.1" - -yargs@^13.2.2, yargs@^13.3.0, yargs@^13.3.2: +yargs@^13.2.2, yargs@^13.3.2: version "13.3.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== @@ -38201,44 +34874,6 @@ yargs@^17.0.0, yargs@^17.6.2: y18n "^5.0.5" yargs-parser "^21.1.1" -yargs@^8.0.2: - version "8.0.2" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-8.0.2.tgz#6299a9055b1cefc969ff7e79c1d918dceb22c360" - integrity sha1-YpmpBVsc78lp/355wdkY3Osiw2A= - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - -yargs@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-9.0.1.tgz#52acc23feecac34042078ee78c0c007f5085db4c" - integrity sha1-UqzCP+7Kw0BCB47njAwAf1CF20w= - dependencies: - camelcase "^4.1.0" - cliui "^3.2.0" - decamelize "^1.1.1" - get-caller-file "^1.0.1" - os-locale "^2.0.0" - read-pkg-up "^2.0.0" - require-directory "^2.1.1" - require-main-filename "^1.0.1" - set-blocking "^2.0.0" - string-width "^2.0.0" - which-module "^2.0.0" - y18n "^3.2.1" - yargs-parser "^7.0.0" - yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"