├── .browserslistrc ├── .circleci └── config.yml ├── .codesandbox └── ci.json ├── .editorconfig ├── .env.sample ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── Bug_report.md │ └── config.yml └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .nvmrc ├── .prettierignore ├── .prettierrc ├── .stylelintrc.json ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── bundlesize.config.json ├── examples ├── github-notification-filters │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── components │ │ ├── FilterHeader.tsx │ │ ├── PanelLayout.tsx │ │ ├── PostfixItem.tsx │ │ ├── PrefixItem.tsx │ │ ├── QueryItem.tsx │ │ ├── TagItem.tsx │ │ └── index.ts │ ├── env.ts │ ├── favicon.png │ ├── global.d.ts │ ├── index.html │ ├── items.ts │ ├── package.json │ ├── searchClient.ts │ ├── style.css │ ├── types │ │ ├── AutocompleteItem.ts │ │ ├── Contributor.ts │ │ ├── NotificationFilter.ts │ │ ├── Repository.ts │ │ └── index.ts │ └── utils │ │ ├── groupBy.ts │ │ └── index.ts ├── github-repositories-custom-plugin │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── createGitHubReposPlugin.tsx │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── html-templates │ ├── README.md │ ├── app.js │ ├── capture.png │ ├── env.js │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── instantsearch │ ├── README.md │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── iphone-banner.png │ ├── package.json │ ├── src │ │ ├── app.ts │ │ ├── autocomplete.tsx │ │ ├── debounce.ts │ │ ├── instantsearch.ts │ │ ├── isModifierEvent.ts │ │ └── searchClient.ts │ └── style.css ├── multiple-datasets-with-headers │ ├── README.md │ ├── app.tsx │ ├── categoriesPlugin.tsx │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── panel-placement │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── playground │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── categoriesPlugin.tsx │ ├── darkMode.ts │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── shortcutsPlugin.tsx │ ├── style.css │ └── types │ │ ├── Highlighted.ts │ │ ├── ProductHit.ts │ │ └── index.ts ├── preview-panel-in-modal │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── query-suggestions-with-categories │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── query-suggestions-with-hits │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── style.css │ └── types │ │ ├── ProductHit.ts │ │ └── index.ts ├── query-suggestions-with-inline-categories │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── query-suggestions-with-recent-searches-and-categories │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── query-suggestions-with-recent-searches │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── query-suggestions │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── react-17 │ ├── .eslintignore │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── Autocomplete.tsx │ │ ├── ClearIcon.tsx │ │ ├── Highlight.tsx │ │ ├── SearchIcon.tsx │ │ ├── index.css │ │ └── index.tsx │ ├── tsconfig.json │ └── vite.config.ts ├── react-instantsearch │ ├── .gitignore │ ├── README.md │ ├── capture.png │ ├── index.html │ ├── package.json │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── components │ │ │ ├── Autocomplete.tsx │ │ │ ├── Hit.tsx │ │ │ └── index.ts │ │ ├── constants.ts │ │ ├── favicon.png │ │ ├── main.tsx │ │ └── widgets │ │ │ └── Panel.tsx │ ├── tsconfig.json │ └── vite.config.ts ├── react │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.png │ ├── src │ │ ├── App.tsx │ │ ├── index.tsx │ │ └── styles.css │ ├── tsconfig.json │ └── vite.config.ts ├── recently-viewed-items │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── recentlyViewedItemsPlugin.tsx │ ├── style.css │ └── types │ │ ├── Highlighted.ts │ │ ├── ProductHit.ts │ │ └── index.ts ├── redirect-url │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── reshape │ ├── README.md │ ├── app.tsx │ ├── env.ts │ ├── favicon.png │ ├── functions │ │ ├── AutocompleteReshapeFunction.ts │ │ ├── groupBy.ts │ │ ├── index.ts │ │ ├── limit.ts │ │ ├── normalizeReshapeSources.ts │ │ └── uniqBy.ts │ ├── index.html │ ├── package.json │ ├── productsPlugin.tsx │ ├── searchClient.ts │ ├── style.css │ └── types │ │ ├── Highlighted.ts │ │ ├── ProductHit.ts │ │ └── index.ts ├── slack-with-emojis-and-commands │ ├── .eslintignore │ ├── .gitignore │ ├── README.md │ ├── capture.png │ ├── index.html │ ├── package.json │ ├── public │ │ ├── avatar.jpg │ │ ├── favicon.png │ │ ├── index.html │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── Autocomplete.tsx │ │ ├── commands.tsx │ │ ├── components │ │ │ ├── CommandsSource.tsx │ │ │ ├── EmojisSource.tsx │ │ │ └── index.ts │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── useAutocomplete.ts │ │ ├── index.css │ │ ├── index.tsx │ │ ├── types │ │ │ ├── Command.ts │ │ │ ├── Emoji.ts │ │ │ ├── SourceProps.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── getActiveToken.ts │ │ │ ├── getCaretCoordinates.ts │ │ │ ├── groupBy.ts │ │ │ ├── index.ts │ │ │ ├── isValidCommandSlug.ts │ │ │ ├── isValidEmojiSlug.ts │ │ │ └── replaceAt.ts │ ├── tsconfig.json │ └── vite.config.ts ├── starter-algolia │ ├── README.md │ ├── app.tsx │ ├── capture.jpg │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── starter │ ├── README.md │ ├── app.tsx │ ├── capture.jpg │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ └── style.css ├── tags-in-searchbox │ ├── README.md │ ├── app.tsx │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── style.css │ └── types │ │ ├── ProductHit.ts │ │ ├── TagExtraData.ts │ │ └── index.ts ├── tags-with-hits │ ├── README.md │ ├── app.tsx │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── style.css │ └── types │ │ ├── ProductHit.ts │ │ ├── TagExtraData.ts │ │ └── index.ts ├── twitter-compose-with-typeahead │ ├── .eslintignore │ ├── .gitignore │ ├── README.md │ ├── capture.png │ ├── index.html │ ├── package.json │ ├── public │ │ ├── favicon.png │ │ ├── manifest.json │ │ └── robots.txt │ ├── src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── Autocomplete.tsx │ │ ├── hooks │ │ │ ├── index.ts │ │ │ └── useAutocomplete.ts │ │ ├── index.css │ │ ├── index.tsx │ │ ├── types │ │ │ ├── Account.ts │ │ │ ├── AutocompleteItem.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── getActiveToken.ts │ │ │ ├── index.ts │ │ │ ├── isValidTwitterUsername.ts │ │ │ └── replaceAt.ts │ ├── tsconfig.json │ └── vite.config.ts ├── two-column-layout │ ├── .gitignore │ ├── README.md │ ├── capture.png │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── src │ │ ├── app.tsx │ │ ├── components │ │ │ ├── Blurhash.tsx │ │ │ ├── Breadcrumb.tsx │ │ │ ├── Icons.tsx │ │ │ └── index.ts │ │ ├── constants.ts │ │ ├── functions │ │ │ ├── createFillWith.ts │ │ │ ├── index.ts │ │ │ ├── normalizeReshapeSources.ts │ │ │ └── uniqBy.ts │ │ ├── plugins │ │ │ ├── articlesPlugin.tsx │ │ │ ├── brandsPlugin.tsx │ │ │ ├── categoriesPlugin.tsx │ │ │ ├── faqPlugin.tsx │ │ │ ├── popularCategoriesPlugin.tsx │ │ │ ├── popularPlugin.tsx │ │ │ ├── productsPlugin.tsx │ │ │ ├── querySuggestionsPlugin.tsx │ │ │ ├── quickAccessPlugin.tsx │ │ │ └── recentSearchesPlugin.tsx │ │ ├── searchClient.ts │ │ ├── types │ │ │ ├── ArticleHit.ts │ │ │ ├── AutocompleteHit.ts │ │ │ ├── AutocompleteReshapeFunction.ts │ │ │ ├── BrandHit.ts │ │ │ ├── CategoryHit.ts │ │ │ ├── FaqHit.ts │ │ │ ├── PopularCategoryHit.ts │ │ │ ├── PopularHit.ts │ │ │ ├── ProductHit.ts │ │ │ ├── QuickAccessHit.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── cx.ts │ │ │ ├── hasSourceActiveItem.ts │ │ │ ├── index.ts │ │ │ ├── intersperse.ts │ │ │ ├── isDetached.ts │ │ │ └── isTouchDevice.ts │ └── style.css ├── voice-search │ ├── README.md │ ├── app.tsx │ ├── capture.png │ ├── env.ts │ ├── favicon.png │ ├── index.html │ ├── package.json │ ├── style.css │ ├── voiceSearchApi.ts │ └── voiceSearchPlugin.tsx ├── vue-instantsearch │ ├── .gitignore │ ├── .prettierrc │ ├── README.md │ ├── babel.config.js │ ├── capture.png │ ├── index.html │ ├── package.json │ ├── public │ │ └── favicon.png │ ├── src │ │ ├── App.vue │ │ ├── Autocomplete.vue │ │ ├── constants.js │ │ ├── main.js │ │ ├── searchClient.js │ │ └── utils │ │ │ └── createElement.js │ └── vite.config.js └── vue │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ └── favicon.png │ ├── src │ ├── App.vue │ ├── components │ │ └── ProductItem.vue │ ├── main.js │ └── utils │ │ └── createElement.js │ ├── style.css │ └── vite.config.js ├── global.d.ts ├── jest.config.js ├── lerna.json ├── media ├── banner.png ├── illustration.png ├── screenshot.png └── showcase │ ├── algolia-documentation.png │ └── docsearch.png ├── netlify.toml ├── package.json ├── packages ├── autocomplete-core │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── autoFocus.test.ts │ │ │ ├── completion.test.ts │ │ │ ├── concurrency.test.ts │ │ │ ├── createAutocomplete.test.ts │ │ │ ├── debouncing.test.ts │ │ │ ├── debug.test.ts │ │ │ ├── defaultSelectedItemId.test.ts │ │ │ ├── environment.test.ts │ │ │ ├── getEnvironmentProps.test.ts │ │ │ ├── getFormProps.test.ts │ │ │ ├── getInputProps.test.ts │ │ │ ├── getItemProps.test.ts │ │ │ ├── getLabelProps.test.ts │ │ │ ├── getListProps.test.ts │ │ │ ├── getPanelProps.test.ts │ │ │ ├── getRootProps.test.ts │ │ │ ├── getSources.test.ts │ │ │ ├── id.test.ts │ │ │ ├── initialState.test.ts │ │ │ ├── metadata.test.ts │ │ │ ├── navigator.test.ts │ │ │ ├── onReset.test.ts │ │ │ ├── onStateChange.test.ts │ │ │ ├── onSubmit.test.ts │ │ │ ├── openOnFocus.test.ts │ │ │ ├── placeholder.test.ts │ │ │ ├── plugins.test.ts │ │ │ ├── refresh.test.ts │ │ │ ├── reshape.test.ts │ │ │ ├── setCollections.test.ts │ │ │ ├── setContext.test.ts │ │ │ ├── setIsOpen.test.ts │ │ │ ├── setQuery.test.ts │ │ │ ├── setSelectedItemId.test.ts │ │ │ ├── setStatus.test.ts │ │ │ └── stallThreshold.test.ts │ │ ├── checkOptions.ts │ │ ├── createAutocomplete.ts │ │ ├── createStore.ts │ │ ├── getAutocompleteSetters.ts │ │ ├── getCompletion.ts │ │ ├── getDefaultProps.ts │ │ ├── getPropGetters.ts │ │ ├── index.ts │ │ ├── metadata.ts │ │ ├── onInput.ts │ │ ├── onKeyDown.ts │ │ ├── reshape.ts │ │ ├── resolve.ts │ │ ├── stateReducer.ts │ │ ├── types │ │ │ ├── AutocompleteStore.ts │ │ │ ├── AutocompleteSubscribers.ts │ │ │ └── index.ts │ │ └── utils │ │ │ ├── __tests__ │ │ │ ├── createCancelablePromise.test.ts │ │ │ ├── createCancelablePromiseList.test.ts │ │ │ ├── createConcurrentSafePromise.test.ts │ │ │ ├── getActiveItem.test.ts │ │ │ ├── getNextActiveItemId.test.ts │ │ │ ├── getNormalizedSources.test.ts │ │ │ ├── getPluginSubmitPromise.test.ts │ │ │ ├── isOrContainsNode.test.ts │ │ │ ├── isSamsung.test.ts │ │ │ └── mapToAlgoliaResponse.test.ts │ │ │ ├── createCancelablePromise.ts │ │ │ ├── createCancelablePromiseList.ts │ │ │ ├── createConcurrentSafePromise.ts │ │ │ ├── getActiveItem.ts │ │ │ ├── getAutocompleteElementId.ts │ │ │ ├── getNativeEvent.ts │ │ │ ├── getNextActiveItemId.ts │ │ │ ├── getNormalizedSources.ts │ │ │ ├── getPluginSubmitPromise.ts │ │ │ ├── index.ts │ │ │ ├── isOrContainsNode.ts │ │ │ ├── isSamsung.ts │ │ │ └── mapToAlgoliaResponse.ts │ └── tsconfig.declaration.json ├── autocomplete-js │ ├── README.md │ ├── global.d.ts │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── api.test.ts │ │ │ ├── autocomplete.test.ts │ │ │ ├── classNames.test.ts │ │ │ ├── components.test.tsx │ │ │ ├── container.test.ts │ │ │ ├── createEffectWrapper.test.ts │ │ │ ├── createReactiveWrapper.test.ts │ │ │ ├── detached.test.ts │ │ │ ├── detachedMediaQuery.test.ts │ │ │ ├── fixtures │ │ │ │ ├── products.json │ │ │ │ └── query-suggestions.json │ │ │ ├── getEnvironmentProps.test.ts │ │ │ ├── getFormProps.test.ts │ │ │ ├── getInputProps.test.ts │ │ │ ├── getItemProps.test.ts │ │ │ ├── getLabelProps.test.ts │ │ │ ├── getListProps.test.ts │ │ │ ├── getPanelProps.test.ts │ │ │ ├── getRootProps.test.ts │ │ │ ├── metadata.test.ts │ │ │ ├── panelContainer.test.ts │ │ │ ├── panelPlacement.test.ts │ │ │ ├── positioning.test.ts │ │ │ ├── render.test.ts │ │ │ ├── renderNoResults.test.ts │ │ │ ├── renderer.test.ts │ │ │ ├── requester.test.ts │ │ │ ├── templates.test.tsx │ │ │ └── translations.test.ts │ │ ├── autocomplete.ts │ │ ├── components │ │ │ ├── Highlight.ts │ │ │ ├── ReverseHighlight.ts │ │ │ ├── ReverseSnippet.ts │ │ │ ├── Snippet.ts │ │ │ └── index.ts │ │ ├── createAutocompleteDom.ts │ │ ├── createEffectWrapper.ts │ │ ├── createReactiveWrapper.ts │ │ ├── elements │ │ │ ├── ClearIcon.ts │ │ │ ├── Input.ts │ │ │ ├── LoadingIcon.ts │ │ │ ├── SearchIcon.ts │ │ │ └── index.ts │ │ ├── getCreateDomElement.ts │ │ ├── getDefaultOptions.ts │ │ ├── getPanelPlacementStyle.ts │ │ ├── index.ts │ │ ├── render.tsx │ │ ├── requesters │ │ │ ├── __tests__ │ │ │ │ ├── getAlgoliaFacets.test.ts │ │ │ │ └── getAlgoliaResults.test.ts │ │ │ ├── createAlgoliaRequester.ts │ │ │ ├── getAlgoliaFacets.ts │ │ │ ├── getAlgoliaResults.ts │ │ │ └── index.ts │ │ ├── types │ │ │ ├── AutocompleteApi.ts │ │ │ ├── AutocompleteDom.ts │ │ │ ├── AutocompleteElement.ts │ │ │ └── index.ts │ │ ├── userAgents.ts │ │ └── utils │ │ │ ├── __tests__ │ │ │ ├── getHTMLElement.test.ts │ │ │ ├── mergeDeep.test.ts │ │ │ └── pickBy.test.ts │ │ │ ├── getHTMLElement.ts │ │ │ ├── index.ts │ │ │ ├── mergeClassNames.ts │ │ │ ├── mergeDeep.ts │ │ │ ├── pickBy.ts │ │ │ └── setProperties.ts │ └── tsconfig.declaration.json ├── autocomplete-plugin-algolia-insights │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── createAlgoliaInsightsPlugin.test.ts │ │ │ └── createSearchInsightsApi.test.ts │ │ ├── createAlgoliaInsightsPlugin.ts │ │ ├── createClickedEvent.ts │ │ ├── createSearchInsightsApi.ts │ │ ├── createViewedEvents.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── isAlgoliaInsightsHit.ts │ │ ├── isModernInsightsClient.ts │ │ └── types │ │ │ ├── AlgoliaInsightsHit.ts │ │ │ ├── AutocompleteInsightsApi.ts │ │ │ ├── EventParams.ts │ │ │ ├── InsightsClient.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-plugin-query-suggestions │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ └── createQuerySuggestionsPlugin.test.ts │ │ ├── constants.ts │ │ ├── createQuerySuggestionsPlugin.ts │ │ ├── getTemplates.tsx │ │ ├── index.ts │ │ └── types │ │ │ ├── QuerySuggestionsHit.ts │ │ │ ├── Translations.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-plugin-recent-searches │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ ├── createLocalStorageRecentSearchesPlugin.test.ts │ │ │ └── createRecentSearchesPlugin.test.ts │ │ ├── addHighlightedAttribute.ts │ │ ├── constants.ts │ │ ├── createLocalStorage.ts │ │ ├── createLocalStorageRecentSearchesPlugin.ts │ │ ├── createRecentSearchesPlugin.ts │ │ ├── createStorageApi.ts │ │ ├── getLocalStorage.ts │ │ ├── getTemplates.tsx │ │ ├── index.ts │ │ ├── search.ts │ │ └── types │ │ │ ├── Highlighted.ts │ │ │ ├── HistoryItem.ts │ │ │ ├── RecentSearchesItem.ts │ │ │ ├── Storage.ts │ │ │ ├── StorageApi.ts │ │ │ ├── Translations.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-plugin-redirect-url │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ └── createRedirectUrlPlugin.test.ts │ │ ├── createRedirectUrlPlugin.ts │ │ ├── index.ts │ │ ├── templates.tsx │ │ └── types │ │ │ ├── Redirect.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-plugin-tags │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── __tests__ │ │ │ └── createTagsPlugin.test.tsx │ │ ├── createTags.ts │ │ ├── createTagsPlugin.tsx │ │ ├── index.ts │ │ ├── theme.scss │ │ └── types │ │ │ ├── Tag.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-preset-algolia │ ├── README.md │ ├── package.json │ ├── rollup.config.js │ ├── src │ │ ├── constants │ │ │ └── index.ts │ │ ├── highlight │ │ │ ├── HighlightedHit.ts │ │ │ ├── ParseAlgoliaHitParams.ts │ │ │ ├── ParsedAttribute.ts │ │ │ ├── SnippetedHit.ts │ │ │ ├── __tests__ │ │ │ │ ├── isPartHighlighted.test.ts │ │ │ │ ├── parseAlgoliaHitHighlight.test.ts │ │ │ │ ├── parseAlgoliaHitReverseHighlight.test.ts │ │ │ │ ├── parseAlgoliaHitReverseSnippet.test.ts │ │ │ │ ├── parseAlgoliaHitSnippet.test.ts │ │ │ │ ├── parseAttribute.test.ts │ │ │ │ └── reverseHighlightedParts.test.ts │ │ │ ├── index.ts │ │ │ ├── isPartHighlighted.ts │ │ │ ├── parseAlgoliaHitHighlight.ts │ │ │ ├── parseAlgoliaHitReverseHighlight.ts │ │ │ ├── parseAlgoliaHitReverseSnippet.ts │ │ │ ├── parseAlgoliaHitSnippet.ts │ │ │ ├── parseAttribute.ts │ │ │ └── reverseHighlightedParts.ts │ │ ├── index.ts │ │ ├── requester │ │ │ ├── __tests__ │ │ │ │ ├── createRequester.test.ts │ │ │ │ ├── getAlgoliaFacets.test.ts │ │ │ │ └── getAlgoliaResults.test.ts │ │ │ ├── createAlgoliaRequester.ts │ │ │ ├── createRequester.ts │ │ │ ├── getAlgoliaFacets.ts │ │ │ ├── getAlgoliaResults.ts │ │ │ └── index.ts │ │ ├── search │ │ │ ├── __tests__ │ │ │ │ └── fetchAlgoliaResults.test.ts │ │ │ ├── fetchAlgoliaResults.ts │ │ │ └── index.ts │ │ ├── types │ │ │ └── index.ts │ │ └── utils │ │ │ ├── __tests__ │ │ │ └── getAppIdAndApiKey.test.ts │ │ │ ├── getAppIdAndApiKey.ts │ │ │ └── index.ts │ └── tsconfig.declaration.json ├── autocomplete-shared │ ├── global.d.ts │ ├── package.json │ ├── src │ │ ├── MaybePromise.ts │ │ ├── SearchResponse.ts │ │ ├── UserAgent.ts │ │ ├── __tests__ │ │ │ ├── createRef.test.ts │ │ │ ├── debounce.test.ts │ │ │ ├── decycle.test.ts │ │ │ ├── flatten.test.ts │ │ │ ├── getItemsCount.test.ts │ │ │ ├── invariant.test.ts │ │ │ ├── isEqual.test.ts │ │ │ ├── noop.test.ts │ │ │ ├── safelyRunOnBrowser.test.ts │ │ │ └── warn.test.ts │ │ ├── core │ │ │ ├── AutocompleteApi.ts │ │ │ ├── AutocompleteCollection.ts │ │ │ ├── AutocompleteContext.ts │ │ │ ├── AutocompleteEnvironment.ts │ │ │ ├── AutocompleteNavigator.ts │ │ │ ├── AutocompleteOptions.ts │ │ │ ├── AutocompletePlugin.ts │ │ │ ├── AutocompletePropGetters.ts │ │ │ ├── AutocompleteReshape.ts │ │ │ ├── AutocompleteSetters.ts │ │ │ ├── AutocompleteSource.ts │ │ │ ├── AutocompleteState.ts │ │ │ └── index.ts │ │ ├── createRef.ts │ │ ├── debounce.ts │ │ ├── decycle.ts │ │ ├── flatten.ts │ │ ├── generateAutocompleteId.ts │ │ ├── getAttributeValueByPath.ts │ │ ├── getItemsCount.ts │ │ ├── index.ts │ │ ├── invariant.ts │ │ ├── isEqual.ts │ │ ├── js │ │ │ ├── AutocompleteClassNames.ts │ │ │ ├── AutocompleteCollection.ts │ │ │ ├── AutocompleteComponents.ts │ │ │ ├── AutocompleteOptions.ts │ │ │ ├── AutocompletePlugin.ts │ │ │ ├── AutocompletePropGetters.ts │ │ │ ├── AutocompleteRender.ts │ │ │ ├── AutocompleteRenderer.ts │ │ │ ├── AutocompleteSource.ts │ │ │ ├── AutocompleteState.ts │ │ │ ├── AutocompleteTranslations.ts │ │ │ ├── HighlightHitParams.ts │ │ │ └── index.ts │ │ ├── noop.ts │ │ ├── preset-algolia │ │ │ ├── algoliasearch.ts │ │ │ └── createRequester.ts │ │ ├── safelyRunOnBrowser.ts │ │ ├── userAgents.ts │ │ ├── version.ts │ │ └── warn.ts │ └── tsconfig.declaration.json └── autocomplete-theme-classic │ ├── README.md │ ├── package.json │ └── src │ └── theme.scss ├── postcss.config.mjs ├── renovate.json ├── scripts ├── babel │ ├── __tests__ │ │ └── wrap-warning-with-dev-check.test.js │ └── wrap-warning-with-dev-check.js ├── buildCss.mjs ├── getBundleBanner.mjs ├── jest │ ├── matchers │ │ ├── __tests__ │ │ │ └── toWarnDev.test.ts │ │ ├── index.ts │ │ ├── toWarnDev.d.ts │ │ └── toWarnDev.ts │ └── setupTests.ts └── rollup │ └── config.js ├── ship.config.js ├── test ├── umd.test.ts ├── utils │ ├── castToJestMock.ts │ ├── createApiResponse.ts │ ├── createCollection.ts │ ├── createMatchMedia.ts │ ├── createNavigator.ts │ ├── createPlayground.ts │ ├── createScopeApi.ts │ ├── createSearchClient.ts │ ├── createSource.ts │ ├── createState.ts │ ├── defer.ts │ ├── index.ts │ └── runAllMicroTasks.ts └── versions │ └── index.js ├── tsconfig.declaration.json ├── tsconfig.json ├── website └── _redirects └── yarn.lock /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": ["packages/autocomplete-*"], 3 | "buildCommand": false, 4 | "^": "buildCommand is false because `yarn prepare` is going to build packages anyway.", 5 | "sandboxes": [ 6 | "/examples/github-repositories-custom-plugin", 7 | "/examples/instantsearch", 8 | "/examples/playground", 9 | "/examples/preview-panel-in-modal", 10 | "/examples/react-renderer", 11 | "/examples/starter-algolia", 12 | "/examples/starter", 13 | "/examples/reshape", 14 | "/examples/vue" 15 | ], 16 | "node": "14" 17 | } 18 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | -------------------------------------------------------------------------------- /.env.sample: -------------------------------------------------------------------------------- 1 | GITHUB_TOKEN= 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .parcel-cache 3 | build 4 | coverage 5 | dist 6 | node_modules 7 | examples/twitter-compose-with-typeahead 8 | examples/slack-with-emojis-and-commands 9 | examples/react-instantsearch 10 | examples/vue-instantsearch 11 | examples/react 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Help us improve Autocomplete. 4 | --- 5 | 6 | ## Description 7 | 8 | 9 | 10 | ## Reproduction 11 | 12 | 13 | 14 | [**Preview →**](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/playground?file=/app.tsx) 15 | 16 | **Steps** 17 | 18 | 1. Go to `...` 19 | 2. Click on `...` 20 | 3. Scroll down to `...` 21 | 4. See error 22 | 23 | ## Expected behavior 24 | 25 | 26 | 27 | ## Environment 28 | 29 | - OS: [e.g. Windows / Linux / macOS / iOS / Android] 30 | - Browser: [e.g. Chrome, Safari] 31 | - Autocomplete version: [e.g. 1.0.0] 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Feature request 4 | url: https://github.com/algolia/autocomplete/discussions/new 5 | about: Request a feature to add to Autocomplete. 6 | - name: Ask a question 7 | url: https://github.com/algolia/autocomplete/discussions/new 8 | about: Ask questions and discuss with other community members. 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | **Summary** 7 | 8 | 13 | 14 | **Result** 15 | 16 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated files 2 | node_modules/ 3 | .DS_Store 4 | .eslintcache 5 | *.log 6 | coverage/ 7 | .cache 8 | .parcel-cache 9 | 10 | # Bundle build files 11 | dist/ 12 | 13 | # IDE 14 | .vscode/ 15 | .idea/ 16 | 17 | # Environment files 18 | .env 19 | 20 | !examples/*/.env 21 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 14.21.1 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .parcel-cache 3 | build 4 | coverage 5 | dist 6 | node_modules 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "proseWrap": "never", 3 | "singleQuote": true, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /examples/github-notification-filters/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/github-notification-filters/capture.png -------------------------------------------------------------------------------- /examples/github-notification-filters/components/FilterHeader.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxRuntime classic */ 2 | /** @jsx h */ 3 | import { h, Fragment } from 'preact'; 4 | 5 | export function FilterHeader() { 6 | return ( 7 | 8 | Available filters 9 |
10 | 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /examples/github-notification-filters/components/PrefixItem.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxRuntime classic */ 2 | /** @jsx h */ 3 | import { h } from 'preact'; 4 | 5 | import { AutocompleteItem } from '../types'; 6 | 7 | type PrefixItemProps = { 8 | item: AutocompleteItem; 9 | }; 10 | 11 | export function PrefixItem({ item }: PrefixItemProps) { 12 | return ( 13 |
14 |
15 |
16 |
17 | {item.token}: {item.label} 18 |
19 |
20 |
21 |
22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /examples/github-notification-filters/components/QueryItem.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxRuntime classic */ 2 | /** @jsx h */ 3 | import { h } from 'preact'; 4 | 5 | type QueryItemProps = { 6 | query: string; 7 | }; 8 | 9 | export function QueryItem({ query }: QueryItemProps) { 10 | return ( 11 |
12 |
13 |
14 |
15 | {query} - submit 16 |
17 |
18 |
19 |
20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /examples/github-notification-filters/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './FilterHeader'; 2 | export * from './PanelLayout'; 3 | export * from './PostfixItem'; 4 | export * from './PrefixItem'; 5 | export * from './QueryItem'; 6 | export * from './TagItem'; 7 | -------------------------------------------------------------------------------- /examples/github-notification-filters/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/github-notification-filters/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/github-notification-filters/favicon.png -------------------------------------------------------------------------------- /examples/github-notification-filters/global.d.ts: -------------------------------------------------------------------------------- 1 | import { TagsApi } from '@algolia/autocomplete-plugin-tags'; 2 | 3 | import { NotificationFilter } from './types'; 4 | 5 | declare module '@algolia/autocomplete-core' { 6 | interface AutocompleteContext { 7 | tagsPlugin: TagsApi; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /examples/github-notification-filters/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | GitHub notification filters | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/github-notification-filters/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-github-notification-filters", 3 | "description": "Autocomplete example with GitHub notification filters", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-plugin-tags": "1.19.2", 14 | "@algolia/autocomplete-theme-classic": "1.19.1", 15 | "algoliasearch": "4.16.0", 16 | "preact": "10.13.2", 17 | "qs": "6.11.1" 18 | }, 19 | "devDependencies": { 20 | "parcel": "2.8.3" 21 | }, 22 | "keywords": [ 23 | "algolia", 24 | "autocomplete", 25 | "javascript" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/github-notification-filters/searchClient.ts: -------------------------------------------------------------------------------- 1 | import algoliasearch from 'algoliasearch/lite'; 2 | 3 | const appId = 'latency'; 4 | const apiKey = '147a0e7dbc37d4c4dec9ec31b0f68716'; 5 | 6 | export const searchClient = algoliasearch(appId, apiKey); 7 | -------------------------------------------------------------------------------- /examples/github-notification-filters/types/AutocompleteItem.ts: -------------------------------------------------------------------------------- 1 | export type AutocompleteItem = { 2 | token: string; 3 | label: string; 4 | attribute: string; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/github-notification-filters/types/Contributor.ts: -------------------------------------------------------------------------------- 1 | export type Contributor = { 2 | login: string; 3 | org: string; 4 | avatar_url: string; 5 | id: number; 6 | }; 7 | -------------------------------------------------------------------------------- /examples/github-notification-filters/types/NotificationFilter.ts: -------------------------------------------------------------------------------- 1 | export type NotificationFilter = { 2 | token: string; 3 | value: string; 4 | attribute: string; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/github-notification-filters/types/Repository.ts: -------------------------------------------------------------------------------- 1 | export type Repository = { 2 | name: string; 3 | description: string; 4 | stargazers_count: number; 5 | forks: number; 6 | language: string; 7 | owner: string; 8 | topics: string[]; 9 | created_at: string; 10 | default_branch: string; 11 | homepage: string; 12 | html_url: string; 13 | id: number; 14 | license: string; 15 | open_issues: number; 16 | watchers: number; 17 | }; 18 | -------------------------------------------------------------------------------- /examples/github-notification-filters/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AutocompleteItem'; 2 | export * from './Contributor'; 3 | export * from './NotificationFilter'; 4 | export * from './Repository'; 5 | -------------------------------------------------------------------------------- /examples/github-notification-filters/utils/groupBy.ts: -------------------------------------------------------------------------------- 1 | export function groupBy( 2 | collection: TValue[], 3 | iteratee: (item: TValue) => TKey 4 | ) { 5 | return collection.reduce>((acc, item) => { 6 | const key = iteratee(item); 7 | 8 | if (!acc.hasOwnProperty(key)) { 9 | acc[key] = []; 10 | } 11 | 12 | acc[key].push(item); 13 | 14 | return acc; 15 | }, {} as any); 16 | } 17 | -------------------------------------------------------------------------------- /examples/github-notification-filters/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './groupBy'; 2 | -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/app.tsx: -------------------------------------------------------------------------------- 1 | import { autocomplete } from '@algolia/autocomplete-js'; 2 | 3 | import { createGitHubReposPlugin } from './createGitHubReposPlugin'; 4 | 5 | import '@algolia/autocomplete-theme-classic'; 6 | 7 | const gitHubReposPlugin = createGitHubReposPlugin({ 8 | // eslint-disable-next-line @typescript-eslint/camelcase 9 | per_page: 5, 10 | }); 11 | 12 | autocomplete({ 13 | container: '#autocomplete', 14 | placeholder: 'Search repositories', 15 | plugins: [gitHubReposPlugin], 16 | }); 17 | -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/github-repositories-custom-plugin/capture.png -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/github-repositories-custom-plugin/favicon.png -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Custom GitHub Repositories plugin | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-github-repositories-custom-plugin", 3 | "description": "Autocomplete example with custom GitHub Repositories plugin", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-theme-classic": "1.19.1", 14 | "preact": "10.13.2", 15 | "qs": "6.11.1" 16 | }, 17 | "devDependencies": { 18 | "@types/debounce-promise": "^3.1.6", 19 | "@types/qs": "^6.9.6", 20 | "parcel": "2.8.3" 21 | }, 22 | "keywords": [ 23 | "algolia", 24 | "autocomplete", 25 | "javascript" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/github-repositories-custom-plugin/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/html-templates/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/html-templates/capture.png -------------------------------------------------------------------------------- /examples/html-templates/env.js: -------------------------------------------------------------------------------- 1 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 2 | // apply the Babel config. We therefore need to manually override the constants 3 | // in the app. 4 | // See https://twitter.com/devongovett/status/1134231234605830144 5 | global.__DEV__ = process.env.NODE_ENV !== 'production'; 6 | global.__TEST__ = false; 7 | -------------------------------------------------------------------------------- /examples/html-templates/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/html-templates/favicon.png -------------------------------------------------------------------------------- /examples/html-templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | HTML Templates | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/html-templates/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-html-templates", 3 | "description": "Autocomplete example with HTML templates", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-theme-classic": "1.19.1", 14 | "algoliasearch": "4.16.0" 15 | }, 16 | "devDependencies": { 17 | "@algolia/client-search": "4.16.0", 18 | "parcel": "2.8.3" 19 | }, 20 | "keywords": [ 21 | "algolia", 22 | "autocomplete", 23 | "javascript" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /examples/html-templates/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/instantsearch/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/instantsearch/capture.png -------------------------------------------------------------------------------- /examples/instantsearch/env.ts: -------------------------------------------------------------------------------- 1 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 2 | // apply the Babel config. We therefore need to manually override the constants 3 | // in the app, as well as the React pragmas. 4 | // See https://twitter.com/devongovett/status/1134231234605830144 5 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 6 | (global as any).__TEST__ = false; 7 | -------------------------------------------------------------------------------- /examples/instantsearch/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/instantsearch/favicon.png -------------------------------------------------------------------------------- /examples/instantsearch/iphone-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/instantsearch/iphone-banner.png -------------------------------------------------------------------------------- /examples/instantsearch/src/app.ts: -------------------------------------------------------------------------------- 1 | import '@algolia/autocomplete-theme-classic'; 2 | import '../style.css'; 3 | 4 | import { startAutocomplete } from './autocomplete'; 5 | import { search } from './instantsearch'; 6 | 7 | search.start(); 8 | startAutocomplete(search); 9 | -------------------------------------------------------------------------------- /examples/instantsearch/src/debounce.ts: -------------------------------------------------------------------------------- 1 | export function debounce( 2 | fn: (...params: TParams[]) => void, 3 | time: number 4 | ) { 5 | let timerId: ReturnType | undefined = undefined; 6 | 7 | return function (...args: TParams[]) { 8 | if (timerId) { 9 | clearTimeout(timerId); 10 | } 11 | 12 | timerId = setTimeout(() => fn(...args), time); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /examples/instantsearch/src/isModifierEvent.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Detect when an event is modified with a special key to let the browser 3 | * trigger its default behavior. 4 | */ 5 | export function isModifierEvent( 6 | event: TEvent 7 | ): boolean { 8 | const isMiddleClick = (event as MouseEvent).button === 1; 9 | 10 | return ( 11 | isMiddleClick || 12 | event.altKey || 13 | event.ctrlKey || 14 | event.metaKey || 15 | event.shiftKey 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /examples/instantsearch/src/searchClient.ts: -------------------------------------------------------------------------------- 1 | import algoliasearch from 'algoliasearch/lite'; 2 | 3 | export const searchClient = algoliasearch( 4 | 'latency', 5 | '6be0576ff61c053d5f9a3225e2a90f76' 6 | ); 7 | -------------------------------------------------------------------------------- /examples/multiple-datasets-with-headers/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/multiple-datasets-with-headers/README.md -------------------------------------------------------------------------------- /examples/multiple-datasets-with-headers/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/multiple-datasets-with-headers/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/multiple-datasets-with-headers/favicon.png -------------------------------------------------------------------------------- /examples/multiple-datasets-with-headers/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Multiple Datasets With Headers 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/multiple-datasets-with-headers/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/panel-placement/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/panel-placement/capture.png -------------------------------------------------------------------------------- /examples/panel-placement/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/panel-placement/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/panel-placement/favicon.png -------------------------------------------------------------------------------- /examples/panel-placement/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-panel-placement", 3 | "description": "Autocomplete panel placement example", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-core": "1.19.1", 13 | "@algolia/autocomplete-js": "1.19.2", 14 | "@algolia/autocomplete-theme-classic": "1.19.1", 15 | "algoliasearch": "4.16.0", 16 | "preact": "10.13.2" 17 | }, 18 | "devDependencies": { 19 | "@algolia/client-search": "4.16.0", 20 | "parcel": "2.8.3" 21 | }, 22 | "keywords": [ 23 | "algolia", 24 | "autocomplete", 25 | "javascript" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /examples/panel-placement/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | width: 100%; 19 | display: grid; 20 | grid-template-columns: 400px 1fr 400px; 21 | grid-gap: 10px; 22 | } 23 | 24 | .action { 25 | align-content: center; 26 | } 27 | -------------------------------------------------------------------------------- /examples/playground/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/playground/capture.png -------------------------------------------------------------------------------- /examples/playground/darkMode.ts: -------------------------------------------------------------------------------- 1 | function initTheme() { 2 | if (isDarkThemeSelected()) { 3 | applyDarkTheme(); 4 | } else { 5 | applyLightTheme(); 6 | } 7 | } 8 | 9 | export function isDarkThemeSelected() { 10 | return localStorage.getItem('darkMode') === 'dark'; 11 | } 12 | 13 | function applyDarkTheme() { 14 | document.body.setAttribute('data-theme', 'dark'); 15 | localStorage.setItem('darkMode', 'dark'); 16 | } 17 | 18 | function applyLightTheme() { 19 | document.body.removeAttribute('data-theme'); 20 | localStorage.removeItem('darkMode'); 21 | } 22 | 23 | export function toggleTheme() { 24 | if (isDarkThemeSelected()) { 25 | applyLightTheme(); 26 | } else { 27 | applyDarkTheme(); 28 | } 29 | } 30 | 31 | initTheme(); 32 | -------------------------------------------------------------------------------- /examples/playground/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/playground/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/playground/favicon.png -------------------------------------------------------------------------------- /examples/playground/types/Highlighted.ts: -------------------------------------------------------------------------------- 1 | import { HighlightResult } from '@algolia/client-search'; 2 | 3 | export type Highlighted = TRecord & { 4 | _highlightResult: HighlightResult; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/playground/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Highlighted'; 2 | export * from './ProductHit'; 3 | -------------------------------------------------------------------------------- /examples/preview-panel-in-modal/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/preview-panel-in-modal/capture.png -------------------------------------------------------------------------------- /examples/preview-panel-in-modal/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/preview-panel-in-modal/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/preview-panel-in-modal/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-categories/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-categories/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-categories/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-categories/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-categories/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-categories/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions with categories | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-categories/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-hits/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-hits/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions with hits | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/types/ProductHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | type ProductRecord = { 4 | brand: string; 5 | categories: string[]; 6 | description: string; 7 | image: string; 8 | name: string; 9 | price: number; 10 | rating: number; 11 | url: string; 12 | }; 13 | 14 | type WithAutocompleteAnalytics = THit & { 15 | __autocomplete_indexName: string; 16 | __autocomplete_queryID: string; 17 | }; 18 | 19 | export type ProductHit = WithAutocompleteAnalytics>; 20 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-hits/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProductHit'; 2 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-inline-categories/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-inline-categories/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-inline-categories/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-inline-categories/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-inline-categories/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-inline-categories/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions with inline categories | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-inline-categories/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches-and-categories/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-recent-searches-and-categories/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches-and-categories/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches-and-categories/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-recent-searches-and-categories/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches-and-categories/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions with recent searches and categories 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches-and-categories/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-recent-searches/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions-with-recent-searches/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions with Recent Searches | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions-with-recent-searches/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/query-suggestions/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions/capture.png -------------------------------------------------------------------------------- /examples/query-suggestions/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/query-suggestions/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/query-suggestions/favicon.png -------------------------------------------------------------------------------- /examples/query-suggestions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Query Suggestions | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/query-suggestions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-query-suggestions", 3 | "description": "Autocomplete example with Query Suggestions", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-plugin-query-suggestions": "1.19.2", 14 | "@algolia/autocomplete-theme-classic": "1.19.1", 15 | "algoliasearch": "4.16.0", 16 | "preact": "10.13.2" 17 | }, 18 | "devDependencies": { 19 | "parcel": "2.8.3" 20 | }, 21 | "keywords": [ 22 | "algolia", 23 | "autocomplete", 24 | "javascript" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/query-suggestions/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/react-17/.eslintignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /examples/react-17/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/react-17/README.md: -------------------------------------------------------------------------------- 1 | # Autocomplete with React 17 example 2 | 3 | This example shows how to integrate Autocomplete with React 17. 4 | 5 | ## Demo 6 | 7 | [Access the demo](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/react-17) 8 | 9 | ## How to run this example locally 10 | 11 | ### 1. Clone this repository 12 | 13 | ```sh 14 | git clone git@github.com:algolia/autocomplete.git 15 | ``` 16 | 17 | ### 2. Install the dependencies and run the server 18 | 19 | ```sh 20 | yarn 21 | yarn workspace @algolia/autocomplete-example-react-17 start 22 | ``` 23 | 24 | Alternatively, you may use npm: 25 | 26 | ```sh 27 | cd examples/react-17 28 | npm install 29 | npm start 30 | ``` 31 | 32 | Open to see your app. 33 | -------------------------------------------------------------------------------- /examples/react-17/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | React 17 | Autocomplete 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/react-17/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/react-17/public/favicon.png -------------------------------------------------------------------------------- /examples/react-17/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React Renderer", 3 | "name": "Autocomplete React Renderer", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/react-17/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/react-17/src/App.css: -------------------------------------------------------------------------------- 1 | .container { 2 | margin: 0 auto; 3 | max-width: 640px; 4 | width: 100%; 5 | } 6 | 7 | .aa-Panel { 8 | max-width: 640px; 9 | width: 100%; 10 | } 11 | -------------------------------------------------------------------------------- /examples/react-17/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Autocomplete } from './Autocomplete'; 4 | import './App.css'; 5 | 6 | export function App() { 7 | return ( 8 |
9 | 10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /examples/react-17/src/ClearIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function ClearIcon(props: React.SVGProps) { 4 | return ( 5 | 12 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /examples/react-17/src/SearchIcon.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export function SearchIcon(props: React.SVGProps) { 4 | return ( 5 | 6 | 15 | 16 | ); 17 | } 18 | -------------------------------------------------------------------------------- /examples/react-17/src/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem 0; 14 | } 15 | -------------------------------------------------------------------------------- /examples/react-17/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import '@algolia/autocomplete-theme-classic'; 5 | 6 | import './index.css'; 7 | import { App } from './App'; 8 | 9 | ReactDOM.render( 10 | 11 | 12 | , 13 | document.getElementById('root') 14 | ); 15 | -------------------------------------------------------------------------------- /examples/react-17/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/react-17/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react'; 2 | import { defineConfig } from 'vite'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/react-instantsearch/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/react-instantsearch/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/react-instantsearch/capture.png -------------------------------------------------------------------------------- /examples/react-instantsearch/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Autocomplete'; 2 | export * from './Hit'; 3 | -------------------------------------------------------------------------------- /examples/react-instantsearch/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const INSTANT_SEARCH_INDEX_NAME = 'instant_search'; 2 | export const INSTANT_SEARCH_QUERY_SUGGESTIONS = 3 | 'instant_search_demo_query_suggestions'; 4 | export const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTES = [ 5 | 'hierarchicalCategories.lvl0', 6 | 'hierarchicalCategories.lvl1', 7 | ]; 8 | -------------------------------------------------------------------------------- /examples/react-instantsearch/src/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/react-instantsearch/src/favicon.png -------------------------------------------------------------------------------- /examples/react-instantsearch/src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | 4 | import App from './App'; 5 | 6 | const root = ReactDOM.createRoot( 7 | document.getElementById('root') as HTMLElement 8 | ); 9 | root.render( 10 | 11 | 12 | 13 | ); 14 | -------------------------------------------------------------------------------- /examples/react-instantsearch/src/widgets/Panel.tsx: -------------------------------------------------------------------------------- 1 | export function Panel({ 2 | children, 3 | header, 4 | footer, 5 | }: React.PropsWithChildren<{ 6 | header?: React.ReactNode; 7 | footer?: React.ReactNode; 8 | }>) { 9 | return ( 10 |
11 | {header &&
{header}
} 12 |
{children}
13 | {footer &&
{footer}
} 14 |
15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /examples/react-instantsearch/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": true, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"], 20 | } 21 | -------------------------------------------------------------------------------- /examples/react-instantsearch/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/react/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/react/README.md: -------------------------------------------------------------------------------- 1 | # Autocomplete with React example 2 | 3 | This example shows how to integrate Autocomplete with [React 18](https://reactjs.org/blog/2022/03/29/react-v18.html). 4 | 5 | ## Demo 6 | 7 | [Access the demo](https://codesandbox.io/s/github/algolia/autocomplete/tree/next/examples/react) 8 | 9 | ## How to run this example locally 10 | 11 | ### 1. Clone this repository 12 | 13 | ```sh 14 | git clone git@github.com:algolia/autocomplete.git 15 | ``` 16 | 17 | ### 2. Install the dependencies and run the server 18 | 19 | ```sh 20 | yarn 21 | yarn workspace @algolia/autocomplete-example-react start 22 | ``` 23 | 24 | Alternatively, you may use npm: 25 | 26 | ```sh 27 | cd examples/react 28 | npm install 29 | npm start 30 | ``` 31 | 32 | Open to see your app. 33 | -------------------------------------------------------------------------------- /examples/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | React | Autocomplete 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/react/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/react/public/favicon.png -------------------------------------------------------------------------------- /examples/react/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom/client'; 3 | import App from './App'; 4 | 5 | import './styles.css'; 6 | 7 | const root = ReactDOM.createRoot( 8 | document.getElementById('root') as HTMLElement 9 | ); 10 | root.render( 11 | 12 | 13 | 14 | ); 15 | -------------------------------------------------------------------------------- /examples/react/src/styles.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 9 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/recently-viewed-items/capture.png -------------------------------------------------------------------------------- /examples/recently-viewed-items/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/recently-viewed-items/favicon.png -------------------------------------------------------------------------------- /examples/recently-viewed-items/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Recently Viewed Items | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/types/Highlighted.ts: -------------------------------------------------------------------------------- 1 | export type Highlighted = TItem & { 2 | _highlightResult: { 3 | label: { 4 | value: string; 5 | }; 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/types/ProductHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | export type ProductItem = { 4 | name: string; 5 | image: string; 6 | url: string; 7 | description: string; 8 | }; 9 | 10 | export type ProductHit = Hit & { 11 | __autocomplete_indexName: string; 12 | __autocomplete_queryID: string; 13 | }; 14 | -------------------------------------------------------------------------------- /examples/recently-viewed-items/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Highlighted'; 2 | export * from './ProductHit'; 3 | -------------------------------------------------------------------------------- /examples/redirect-url/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/redirect-url/capture.png -------------------------------------------------------------------------------- /examples/redirect-url/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/redirect-url/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/redirect-url/favicon.png -------------------------------------------------------------------------------- /examples/redirect-url/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Redirect URL | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/redirect-url/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-redirect-url", 3 | "description": "Autocomplete example for Redirect URL plugin", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-plugin-redirect-url": "1.19.2", 14 | "@algolia/autocomplete-theme-classic": "1.19.1", 15 | "algoliasearch": "4.16.0", 16 | "preact": "10.13.2" 17 | }, 18 | "devDependencies": { 19 | "parcel": "2.8.3" 20 | }, 21 | "keywords": [ 22 | "algolia", 23 | "autocomplete", 24 | "javascript" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/redirect-url/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/reshape/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/reshape/README.md -------------------------------------------------------------------------------- /examples/reshape/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/reshape/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/reshape/favicon.png -------------------------------------------------------------------------------- /examples/reshape/functions/AutocompleteReshapeFunction.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteReshapeSource, 3 | BaseItem, 4 | } from '@algolia/autocomplete-core'; 5 | 6 | export type AutocompleteReshapeFunction = < 7 | TItem extends BaseItem 8 | >( 9 | ...params: TParams[] 10 | ) => ( 11 | ...expressions: Array> 12 | ) => Array>; 13 | -------------------------------------------------------------------------------- /examples/reshape/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './groupBy'; 2 | export * from './limit'; 3 | export * from './uniqBy'; 4 | -------------------------------------------------------------------------------- /examples/reshape/functions/normalizeReshapeSources.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteReshapeSource, 3 | BaseItem, 4 | } from '@algolia/autocomplete-core'; 5 | import { flatten } from '@algolia/autocomplete-shared'; 6 | 7 | // We filter out falsy values because dynamic sources may not exist at every render. 8 | // We flatten to support pipe operators from functional libraries like Ramda. 9 | export function normalizeReshapeSources( 10 | sources: Array> 11 | ) { 12 | return flatten(sources).filter(Boolean); 13 | } 14 | -------------------------------------------------------------------------------- /examples/reshape/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Reshape API | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/reshape/searchClient.ts: -------------------------------------------------------------------------------- 1 | import algoliasearch from 'algoliasearch/lite'; 2 | 3 | const appId = 'latency'; 4 | const apiKey = '6be0576ff61c053d5f9a3225e2a90f76'; 5 | 6 | export const searchClient = algoliasearch(appId, apiKey); 7 | -------------------------------------------------------------------------------- /examples/reshape/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | 22 | body[data-theme='dark'] { 23 | background-color: rgb(0, 0, 0); 24 | color: rgb(183, 192, 199); 25 | } 26 | -------------------------------------------------------------------------------- /examples/reshape/types/Highlighted.ts: -------------------------------------------------------------------------------- 1 | import { HighlightResult } from '@algolia/client-search'; 2 | 3 | export type Highlighted = TRecord & { 4 | _highlightResult: HighlightResult; 5 | }; 6 | -------------------------------------------------------------------------------- /examples/reshape/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Highlighted'; 2 | export * from './ProductHit'; 3 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/.eslintignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/slack-with-emojis-and-commands/capture.png -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Slack with emojis and slash commands | Autocomplete 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/public/avatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/slack-with-emojis-and-commands/public/avatar.jpg -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/slack-with-emojis-and-commands/public/favicon.png -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Slack with emojis and slash commands | Autocomplete 12 | 13 | 14 | 15 |
16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Slack", 3 | "name": "Slack with emojis and slash commands | Autocomplete", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Autocomplete } from './Autocomplete'; 4 | 5 | import './App.css'; 6 | 7 | export function App() { 8 | return ( 9 |
10 | 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommandsSource'; 2 | export * from './EmojisSource'; 3 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useAutocomplete'; 2 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import { App } from './App'; 5 | 6 | import './index.css'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/types/Command.ts: -------------------------------------------------------------------------------- 1 | import type { JSX } from 'react'; 2 | 3 | export type Command = { 4 | slug: string; 5 | commands: string[]; 6 | icon: JSX.Element; 7 | description: string; 8 | }; 9 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/types/Emoji.ts: -------------------------------------------------------------------------------- 1 | export type Emoji = { 2 | name: string; 3 | slug: string; 4 | group: string; 5 | emoji_version: string; 6 | unicode_version: string; 7 | skin_tone_support: boolean; 8 | symbol: string; 9 | }; 10 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/types/SourceProps.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteApi, 3 | BaseItem, 4 | InternalAutocompleteSource, 5 | } from '@algolia/autocomplete-core'; 6 | 7 | export type SourceProps = { 8 | source: InternalAutocompleteSource; 9 | items: TItem[]; 10 | autocomplete: AutocompleteApi< 11 | TItem, 12 | React.BaseSyntheticEvent, 13 | React.MouseEvent, 14 | React.KeyboardEvent 15 | >; 16 | }; 17 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Command'; 2 | export * from './Emoji'; 3 | export * from './SourceProps'; 4 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/getActiveToken.ts: -------------------------------------------------------------------------------- 1 | export function getActiveToken(input: string, cursorPosition: number) { 2 | const tokenizedQuery = input.split(/[\s\n]/).reduce((acc, word, index) => { 3 | const previous = acc[index - 1]; 4 | const start = index === 0 ? index : previous.range[1] + 1; 5 | const end = start + word.length; 6 | 7 | return acc.concat([{ word, range: [start, end] }]); 8 | }, [] as Array<{ word: string; range: [number, number] }>); 9 | 10 | if (cursorPosition === undefined) { 11 | return undefined; 12 | } 13 | 14 | const activeToken = tokenizedQuery.find( 15 | ({ range }) => range[0] < cursorPosition && range[1] >= cursorPosition 16 | ); 17 | 18 | return activeToken; 19 | } 20 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/getCaretCoordinates.ts: -------------------------------------------------------------------------------- 1 | import textareaCaret from 'textarea-caret'; 2 | 3 | export function getCaretCoordinates(inputRef: HTMLTextAreaElement | null) { 4 | return inputRef 5 | ? textareaCaret(inputRef, inputRef?.selectionEnd) 6 | : { top: 0, height: 0 }; 7 | } 8 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/groupBy.ts: -------------------------------------------------------------------------------- 1 | export function groupBy( 2 | collection: TValue[], 3 | iteratee: (item: TValue) => TKey 4 | ) { 5 | return collection.reduce>((acc, item) => { 6 | const key = iteratee(item); 7 | 8 | if (!acc.hasOwnProperty(key)) { 9 | // eslint-disable-next-line no-param-reassign 10 | acc[key] = []; 11 | } 12 | 13 | acc[key].push(item); 14 | 15 | return acc; 16 | }, {} as any); 17 | } 18 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getActiveToken'; 2 | export * from './getCaretCoordinates'; 3 | export * from './groupBy'; 4 | export * from './isValidCommandSlug'; 5 | export * from './isValidEmojiSlug'; 6 | export * from './replaceAt'; 7 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/isValidCommandSlug.ts: -------------------------------------------------------------------------------- 1 | export function isValidCommandSlug(token: string) { 2 | return /^\/[a-z]?/.test(token); 3 | } 4 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/isValidEmojiSlug.ts: -------------------------------------------------------------------------------- 1 | export function isValidEmojiSlug(token: string) { 2 | return /^:[a-z-_]+:?$/.test(token); 3 | } 4 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/src/utils/replaceAt.ts: -------------------------------------------------------------------------------- 1 | export function replaceAt( 2 | str: string, 3 | replacement: string, 4 | index: number, 5 | length = 0 6 | ) { 7 | const prefix = str.substr(0, index); 8 | const suffix = str.substr(index + length); 9 | 10 | return prefix + replacement + suffix; 11 | } 12 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/slack-with-emojis-and-commands/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/starter-algolia/capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/starter-algolia/capture.jpg -------------------------------------------------------------------------------- /examples/starter-algolia/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/starter-algolia/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/starter-algolia/favicon.png -------------------------------------------------------------------------------- /examples/starter-algolia/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Algolia Starter | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/starter-algolia/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-starter-algolia", 3 | "description": "Autocomplete Algolia starter", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-theme-classic": "1.19.1", 14 | "algoliasearch": "4.16.0", 15 | "preact": "10.13.2" 16 | }, 17 | "devDependencies": { 18 | "@algolia/client-search": "4.16.0", 19 | "parcel": "2.8.3" 20 | }, 21 | "keywords": [ 22 | "algolia", 23 | "autocomplete", 24 | "javascript" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/starter-algolia/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/starter/capture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/starter/capture.jpg -------------------------------------------------------------------------------- /examples/starter/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/starter/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/starter/favicon.png -------------------------------------------------------------------------------- /examples/starter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Starter | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/starter/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-starter", 3 | "description": "Autocomplete starter", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-theme-classic": "1.19.1", 14 | "preact": "10.13.2" 15 | }, 16 | "devDependencies": { 17 | "parcel": "2.8.3" 18 | }, 19 | "keywords": [ 20 | "algolia", 21 | "autocomplete", 22 | "javascript" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /examples/starter/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | 16 | .container { 17 | margin: 0 auto; 18 | max-width: 640px; 19 | width: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /examples/tags-in-searchbox/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/tags-in-searchbox/README.md -------------------------------------------------------------------------------- /examples/tags-in-searchbox/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/tags-in-searchbox/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/tags-in-searchbox/favicon.png -------------------------------------------------------------------------------- /examples/tags-in-searchbox/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Tags in the searchbox | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/tags-in-searchbox/types/ProductHit.ts: -------------------------------------------------------------------------------- 1 | import { AlgoliaInsightsHit } from '@algolia/autocomplete-js'; 2 | import { Hit } from '@algolia/client-search'; 3 | 4 | type ProductRecord = { 5 | brand: string; 6 | categories: string[]; 7 | description: string; 8 | image: string; 9 | name: string; 10 | price: number; 11 | rating: number; 12 | url: string; 13 | }; 14 | 15 | export type ProductHit = AlgoliaInsightsHit & Hit; 16 | -------------------------------------------------------------------------------- /examples/tags-in-searchbox/types/TagExtraData.ts: -------------------------------------------------------------------------------- 1 | export type TagExtraData = { facet: string }; 2 | -------------------------------------------------------------------------------- /examples/tags-in-searchbox/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProductHit'; 2 | export * from './TagExtraData'; 3 | -------------------------------------------------------------------------------- /examples/tags-with-hits/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/tags-with-hits/README.md -------------------------------------------------------------------------------- /examples/tags-with-hits/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/tags-with-hits/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/tags-with-hits/favicon.png -------------------------------------------------------------------------------- /examples/tags-with-hits/types/ProductHit.ts: -------------------------------------------------------------------------------- 1 | import { AlgoliaInsightsHit } from '@algolia/autocomplete-js'; 2 | import { Hit } from '@algolia/client-search'; 3 | 4 | type ProductRecord = { 5 | brand: string; 6 | categories: string[]; 7 | description: string; 8 | image: string; 9 | name: string; 10 | price: number; 11 | rating: number; 12 | url: string; 13 | }; 14 | 15 | export type ProductHit = Hit & AlgoliaInsightsHit; 16 | -------------------------------------------------------------------------------- /examples/tags-with-hits/types/TagExtraData.ts: -------------------------------------------------------------------------------- 1 | export type TagExtraData = { facet: string }; 2 | -------------------------------------------------------------------------------- /examples/tags-with-hits/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProductHit'; 2 | export * from './TagExtraData'; 3 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/.eslintignore: -------------------------------------------------------------------------------- 1 | * 2 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/twitter-compose-with-typeahead/capture.png -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Twitter compose box with mentions typeahead | Autocomplete 10 | 11 | 12 |
13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/twitter-compose-with-typeahead/public/favicon.png -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Twitter mentions", 3 | "name": "Twitter compose box with mentions typeahead | Autocomplete", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | import { Autocomplete } from './Autocomplete'; 4 | 5 | import './App.css'; 6 | 7 | export function App() { 8 | return ( 9 |
10 | 11 |
12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useAutocomplete'; 2 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/index.css: -------------------------------------------------------------------------------- 1 | *, 2 | ::before, 3 | ::after { 4 | box-sizing: border-box; 5 | border-width: 0; 6 | border-style: solid; 7 | border-color: currentColor; 8 | } 9 | 10 | html { 11 | -moz-tab-size: 4; 12 | tab-size: 4; 13 | line-height: 1.5; 14 | -webkit-text-size-adjust: 100%; 15 | } 16 | 17 | body { 18 | margin: 0; 19 | font-family: system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, 20 | sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji'; 21 | } 22 | 23 | button, 24 | textarea { 25 | font-family: inherit; 26 | font-size: 100%; 27 | margin: 0; 28 | padding: 0; 29 | line-height: inherit; 30 | color: inherit; 31 | } 32 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import { App } from './App'; 5 | 6 | import './index.css'; 7 | 8 | ReactDOM.render( 9 | 10 | 11 | , 12 | document.getElementById('root') 13 | ); 14 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/types/Account.ts: -------------------------------------------------------------------------------- 1 | export type Account = { 2 | name: string; 3 | handle: string; 4 | image: string; 5 | verified: boolean; 6 | follows_me: boolean; 7 | followed_by_me: boolean; 8 | followers: number; 9 | following: number; 10 | }; 11 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/types/AutocompleteItem.ts: -------------------------------------------------------------------------------- 1 | import type { Hit } from '@algolia/client-search'; 2 | 3 | import type { Account } from '.'; 4 | 5 | export type AutocompleteItem = Hit; 6 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Account'; 2 | export * from './AutocompleteItem'; 3 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/utils/getActiveToken.ts: -------------------------------------------------------------------------------- 1 | export function getActiveToken(input: string, cursorPosition: number) { 2 | const tokenizedQuery = input.split(/[\s\n]/).reduce((acc, word, index) => { 3 | const previous = acc[index - 1]; 4 | const start = index === 0 ? index : previous.range[1] + 1; 5 | const end = start + word.length; 6 | 7 | return acc.concat([{ word, range: [start, end] }]); 8 | }, [] as Array<{ word: string; range: [number, number] }>); 9 | 10 | if (cursorPosition === undefined) { 11 | return undefined; 12 | } 13 | 14 | const activeToken = tokenizedQuery.find( 15 | ({ range }) => range[0] < cursorPosition && range[1] >= cursorPosition 16 | ); 17 | 18 | return activeToken; 19 | } 20 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getActiveToken'; 2 | export * from './isValidTwitterUsername'; 3 | export * from './replaceAt'; 4 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/utils/isValidTwitterUsername.ts: -------------------------------------------------------------------------------- 1 | export function isValidTwitterUsername(username: string) { 2 | return /^@\w{1,15}$/.test(username); 3 | } 4 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/src/utils/replaceAt.ts: -------------------------------------------------------------------------------- 1 | export function replaceAt( 2 | str: string, 3 | replacement: string, 4 | index: number, 5 | length = 0 6 | ) { 7 | const prefix = str.substr(0, index); 8 | const suffix = str.substr(index + length); 9 | 10 | return prefix + replacement + suffix; 11 | } 12 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["dom", "dom.iterable", "esnext"], 5 | "allowJs": true, 6 | "skipLibCheck": true, 7 | "esModuleInterop": true, 8 | "allowSyntheticDefaultImports": true, 9 | "strict": true, 10 | "forceConsistentCasingInFileNames": true, 11 | "noFallthroughCasesInSwitch": true, 12 | "module": "esnext", 13 | "moduleResolution": "node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react-jsx" 18 | }, 19 | "include": ["src"] 20 | } 21 | -------------------------------------------------------------------------------- /examples/twitter-compose-with-typeahead/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import react from '@vitejs/plugin-react'; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [react()], 7 | }); 8 | -------------------------------------------------------------------------------- /examples/two-column-layout/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /dist 11 | /.cache 12 | /.parcel-cache 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /examples/two-column-layout/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/two-column-layout/capture.png -------------------------------------------------------------------------------- /examples/two-column-layout/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/two-column-layout/favicon.png -------------------------------------------------------------------------------- /examples/two-column-layout/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Autocomplete with a two-column layout 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/components/Breadcrumb.tsx: -------------------------------------------------------------------------------- 1 | /** @jsxRuntime classic */ 2 | /** @jsx h */ 3 | import { h } from 'preact'; 4 | 5 | import { intersperse } from '../utils'; 6 | 7 | import { ChevronRightIcon } from './Icons'; 8 | 9 | type BreadcrumbProps = { 10 | items: h.JSX.Element[]; 11 | }; 12 | 13 | export function Breadcrumb({ items }: BreadcrumbProps) { 14 | return ( 15 |
16 | {intersperse( 17 | items, 18 |
19 | 20 |
21 | )} 22 |
23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Icons'; 2 | export * from './Blurhash'; 3 | export * from './Breadcrumb'; 4 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/constants.ts: -------------------------------------------------------------------------------- 1 | export const ALGOLIA_PRODUCTS_INDEX_NAME = 'autocomplete_demo_products'; 2 | export const ALGOLIA_PRODUCTS_QUERY_SUGGESTIONS_INDEX_NAME = 3 | 'autocomplete_demo_products_query_suggestions'; 4 | export const ALGOLIA_ARTICLES_INDEX_NAME = 'autocomplete_demo_articles'; 5 | export const ALGOLIA_FAQ_INDEX_NAME = 'autocomplete_demo_faq'; 6 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/functions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './uniqBy'; 2 | export * from './createFillWith'; 3 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/functions/normalizeReshapeSources.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteReshapeSource, 3 | BaseItem, 4 | } from '@algolia/autocomplete-core'; 5 | import { flatten } from '@algolia/autocomplete-shared'; 6 | 7 | // We filter out falsy values because dynamic sources may not exist at every render. 8 | // We flatten to support pipe operators from functional libraries like Ramda. 9 | export function normalizeReshapeSources( 10 | sources: Array> 11 | ) { 12 | return flatten(sources).filter(Boolean); 13 | } 14 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/plugins/querySuggestionsPlugin.tsx: -------------------------------------------------------------------------------- 1 | import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions'; 2 | 3 | import { ALGOLIA_PRODUCTS_QUERY_SUGGESTIONS_INDEX_NAME } from '../constants'; 4 | import { searchClient } from '../searchClient'; 5 | 6 | export const querySuggestionsPlugin = createQuerySuggestionsPlugin({ 7 | searchClient, 8 | indexName: ALGOLIA_PRODUCTS_QUERY_SUGGESTIONS_INDEX_NAME, 9 | getSearchParams({ state }) { 10 | return { 11 | hitsPerPage: !state.query ? 0 : 10, 12 | }; 13 | }, 14 | }); 15 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/plugins/recentSearchesPlugin.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | createLocalStorageRecentSearchesPlugin, 3 | search, 4 | } from '@algolia/autocomplete-plugin-recent-searches'; 5 | 6 | export const recentSearchesPlugin = createLocalStorageRecentSearchesPlugin({ 7 | key: 'autocomplete-two-column-layout-example', 8 | search(params) { 9 | return search({ ...params, limit: params.query ? 1 : 4 }); 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/searchClient.ts: -------------------------------------------------------------------------------- 1 | import algoliasearch from 'algoliasearch/lite'; 2 | 3 | export const searchClient = algoliasearch( 4 | 'latency', 5 | '6be0576ff61c053d5f9a3225e2a90f76' 6 | ); 7 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/ArticleHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | type ArticleRecord = { 4 | title: string; 5 | date: string; 6 | image_url: string; 7 | }; 8 | 9 | export type ArticleHit = Hit; 10 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/AutocompleteHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | export type AutocompleteHit = Hit< 4 | THit & { 5 | __autocomplete_id: number; 6 | } 7 | >; 8 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/AutocompleteReshapeFunction.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteReshapeSource, 3 | BaseItem, 4 | } from '@algolia/autocomplete-core'; 5 | 6 | export type AutocompleteReshapeFunction = < 7 | TItem extends BaseItem 8 | >( 9 | ...params: TParams[] 10 | ) => ( 11 | ...expressions: Array> 12 | ) => Array>; 13 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/BrandHit.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteHit } from './AutocompleteHit'; 2 | 3 | type BrandRecord = { 4 | label: string; 5 | count: number; 6 | }; 7 | 8 | export type BrandHit = AutocompleteHit; 9 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/CategoryHit.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteHit } from './AutocompleteHit'; 2 | 3 | type CategoryRecord = { 4 | list_categories: string[]; 5 | }; 6 | 7 | export type CategoryHit = AutocompleteHit; 8 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/FaqHit.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteHit } from './AutocompleteHit'; 2 | 3 | type FaqRecord = { 4 | list_categories: string[]; 5 | title: string; 6 | description: string; 7 | }; 8 | 9 | export type FaqHit = AutocompleteHit; 10 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/PopularCategoryHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | type PopularCategoryRecord = { 4 | label: string; 5 | count: number; 6 | }; 7 | 8 | export type PopularCategoryHit = Hit; 9 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/PopularHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | type PopularRecord = { 4 | query: string; 5 | }; 6 | 7 | export type PopularHit = Hit; 8 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/ProductHit.ts: -------------------------------------------------------------------------------- 1 | import type { Hit } from '@algolia/client-search'; 2 | 3 | type ProductRecord = { 4 | name: string; 5 | brand: string; 6 | image_urls: string[]; 7 | image_blurred: string; 8 | price: { 9 | currency: string; 10 | discount_level: number; 11 | discounted_value: number; 12 | on_sales: boolean; 13 | value: number; 14 | }; 15 | reviews: { 16 | count: number; 17 | rating: number; 18 | }; 19 | }; 20 | 21 | export type ProductHit = Hit; 22 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/QuickAccessHit.ts: -------------------------------------------------------------------------------- 1 | import { Hit } from '@algolia/client-search'; 2 | 3 | type QuickAccessRecord = { 4 | template: 'sales-banner' | 'sales-code' | 'new-collection' | 'help'; 5 | href: string; 6 | image: string; 7 | title: string; 8 | subtitle: string; 9 | date?: string; 10 | links?: Array<{ 11 | text: string; 12 | href: string; 13 | }>; 14 | }; 15 | 16 | export type QuickAccessHit = Hit; 17 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ProductHit'; 2 | export * from './CategoryHit'; 3 | export * from './BrandHit'; 4 | export * from './FaqHit'; 5 | export * from './ArticleHit'; 6 | export * from './PopularHit'; 7 | export * from './QuickAccessHit'; 8 | export * from './PopularCategoryHit'; 9 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/cx.ts: -------------------------------------------------------------------------------- 1 | export function cx( 2 | ...classNames: Array 3 | ) { 4 | return classNames.filter(Boolean).join(' '); 5 | } 6 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/hasSourceActiveItem.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteState, BaseItem } from '@algolia/autocomplete-core'; 2 | 3 | export function hasSourceActiveItem( 4 | sourceId: string, 5 | state: AutocompleteState 6 | ) { 7 | return Boolean( 8 | state.collections.find( 9 | (collection) => 10 | collection.source.sourceId === sourceId && 11 | collection.items.find( 12 | (item) => item.__autocomplete_id === state.activeItemId 13 | ) 14 | ) 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './cx'; 2 | export * from './intersperse'; 3 | export * from './isTouchDevice'; 4 | export * from './isDetached'; 5 | export * from './hasSourceActiveItem'; 6 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/intersperse.ts: -------------------------------------------------------------------------------- 1 | export function intersperse( 2 | arr: TItem[], 3 | separator: TSeparator 4 | ) { 5 | return arr.reduce((acc, curr) => [...acc, curr, separator], []).slice(0, -1); 6 | } 7 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/isDetached.ts: -------------------------------------------------------------------------------- 1 | export function isDetached() { 2 | return window.matchMedia( 3 | getComputedStyle(document.documentElement).getPropertyValue( 4 | '--aa-detached-media-query' 5 | ) 6 | ).matches; 7 | } 8 | -------------------------------------------------------------------------------- /examples/two-column-layout/src/utils/isTouchDevice.ts: -------------------------------------------------------------------------------- 1 | export function isTouchDevice() { 2 | return 'ontouchstart' in window; 3 | } 4 | -------------------------------------------------------------------------------- /examples/voice-search/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/voice-search/capture.png -------------------------------------------------------------------------------- /examples/voice-search/env.ts: -------------------------------------------------------------------------------- 1 | import * as preact from 'preact'; 2 | 3 | // Parcel picks the `source` field of the monorepo packages and thus doesn't 4 | // apply the Babel config. We therefore need to manually override the constants 5 | // in the app, as well as the React pragmas. 6 | // See https://twitter.com/devongovett/status/1134231234605830144 7 | (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; 8 | (global as any).__TEST__ = false; 9 | (global as any).h = preact.h; 10 | (global as any).React = preact; 11 | -------------------------------------------------------------------------------- /examples/voice-search/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/voice-search/favicon.png -------------------------------------------------------------------------------- /examples/voice-search/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Voice Search | Autocomplete 10 | 11 | 12 | 13 |
14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/voice-search/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-voice-search", 3 | "description": "Autocomplete example with Voice Search", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "build": "parcel build index.html", 9 | "start": "parcel index.html" 10 | }, 11 | "dependencies": { 12 | "@algolia/autocomplete-js": "1.19.2", 13 | "@algolia/autocomplete-theme-classic": "1.19.1", 14 | "algoliasearch": "4.16.0", 15 | "preact": "10.13.2" 16 | }, 17 | "devDependencies": { 18 | "@algolia/client-search": "4.16.0", 19 | "parcel": "2.8.3" 20 | }, 21 | "keywords": [ 22 | "algolia", 23 | "autocomplete", 24 | "javascript" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "trailingComma": "es5" 4 | } 5 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/capture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/vue-instantsearch/capture.png -------------------------------------------------------------------------------- /examples/vue-instantsearch/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue InstantSearch | Autocomplete 8 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/vue-instantsearch/public/favicon.png -------------------------------------------------------------------------------- /examples/vue-instantsearch/src/constants.js: -------------------------------------------------------------------------------- 1 | export const INSTANT_SEARCH_INDEX_NAME = 'instant_search'; 2 | 3 | export const INSTANT_SEARCH_HIERARCHICAL_ATTRIBUTE = 4 | 'hierarchicalCategories.lvl0'; 5 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import InstantSearch from 'vue-instantsearch/vue3/es'; 3 | import App from './App.vue'; 4 | 5 | const app = createApp(App); 6 | app.use(InstantSearch); 7 | app.mount('#app'); 8 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/src/searchClient.js: -------------------------------------------------------------------------------- 1 | import algoliasearch from 'algoliasearch/lite'; 2 | 3 | export const searchClient = algoliasearch( 4 | 'latency', 5 | '6be0576ff61c053d5f9a3225e2a90f76' 6 | ); 7 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/src/utils/createElement.js: -------------------------------------------------------------------------------- 1 | import { h } from 'vue'; 2 | 3 | export function createElement(type, props, ...children) { 4 | const adaptedProps = Object.entries(props || {}).reduce( 5 | (acc, [key, value]) => { 6 | // Vue 3 accepts lower-case event names so we need to transform props like 7 | // `onMouseMove` to `onMousemove`. 8 | const property = 9 | key[0] === 'o' && key[1] === 'n' 10 | ? key.slice(0, 3) + key.slice(3).toLowerCase() 11 | : key; 12 | 13 | acc[property] = value; 14 | return acc; 15 | }, 16 | {} 17 | ); 18 | 19 | return h(type, adaptedProps, ...children); 20 | } 21 | -------------------------------------------------------------------------------- /examples/vue-instantsearch/vite.config.js: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue'; 2 | import vueJsx from '@vitejs/plugin-vue-jsx'; 3 | import { defineConfig } from 'vite'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue(), vueJsx()], 8 | }); 9 | -------------------------------------------------------------------------------- /examples/vue/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local -------------------------------------------------------------------------------- /examples/vue/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/vue/README.md -------------------------------------------------------------------------------- /examples/vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Vue | Autocomplete 9 | 10 | 11 |
12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /examples/vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@algolia/autocomplete-example-vue", 3 | "description": "Autocomplete with Vue", 4 | "version": "1.19.2", 5 | "private": true, 6 | "license": "MIT", 7 | "scripts": { 8 | "dev": "vite", 9 | "serve": "vite start", 10 | "build": "vite build" 11 | }, 12 | "dependencies": { 13 | "@algolia/autocomplete-js": "1.19.2", 14 | "@algolia/autocomplete-theme-classic": "1.19.1", 15 | "algoliasearch": "4.16.0", 16 | "vue": "3.2.47" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-vue": "1.9.3", 20 | "@vitejs/plugin-vue-jsx": "1.2.0", 21 | "@vue/compiler-sfc": "3.2.47", 22 | "vite": "2.6.4" 23 | }, 24 | "keywords": [ 25 | "algolia", 26 | "autocomplete", 27 | "javascript" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /examples/vue/public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/examples/vue/public/favicon.png -------------------------------------------------------------------------------- /examples/vue/src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | 3 | import App from './App.vue'; 4 | 5 | createApp(App).mount('#app'); 6 | -------------------------------------------------------------------------------- /examples/vue/src/utils/createElement.js: -------------------------------------------------------------------------------- 1 | import { h } from 'vue'; 2 | 3 | export function createElement(type, props, ...children) { 4 | const adaptedProps = Object.entries(props || {}).reduce( 5 | (acc, [key, value]) => { 6 | // Vue 3 accepts lower-case event names so we need to transform props like 7 | // `onMouseMove` to `onMousemove`. 8 | const property = 9 | key[0] === 'o' && key[1] === 'n' 10 | ? key.slice(0, 3) + key.slice(3).toLowerCase() 11 | : key; 12 | 13 | acc[property] = value; 14 | return acc; 15 | }, 16 | {} 17 | ); 18 | 19 | return h(type, adaptedProps, ...children); 20 | } 21 | -------------------------------------------------------------------------------- /examples/vue/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | body { 6 | background-color: rgb(244, 244, 249); 7 | color: rgb(65, 65, 65); 8 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 9 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 10 | sans-serif; 11 | -webkit-font-smoothing: antialiased; 12 | -moz-osx-font-smoothing: grayscale; 13 | padding: 1rem; 14 | } 15 | -------------------------------------------------------------------------------- /examples/vue/vite.config.js: -------------------------------------------------------------------------------- 1 | import vue from '@vitejs/plugin-vue'; 2 | import vueJsx from '@vitejs/plugin-vue-jsx'; 3 | import { defineConfig } from 'vite'; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [vue(), vueJsx()], 8 | }); 9 | -------------------------------------------------------------------------------- /global.d.ts: -------------------------------------------------------------------------------- 1 | declare const __DEV__: boolean; 2 | declare const __TEST__: boolean; 3 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rootDir: process.cwd(), 3 | setupFilesAfterEnv: [ 4 | '@testing-library/jest-dom/extend-expect', 5 | './scripts/jest/setupTests.ts', 6 | ], 7 | testPathIgnorePatterns: ['node_modules/', 'dist/'], 8 | coveragePathIgnorePatterns: ['node_modules/', 'dist/'], 9 | watchPlugins: [ 10 | 'jest-watch-typeahead/filename', 11 | 'jest-watch-typeahead/testname', 12 | ], 13 | globals: { 14 | __DEV__: true, 15 | __TEST__: true, 16 | }, 17 | moduleNameMapper: { 18 | '^@algolia/autocomplete-shared/dist/esm/(.*)$': 19 | '/packages/autocomplete-shared/src/$1', 20 | '^@algolia/autocomplete-(.*)$': '/packages/autocomplete-$1/src/', 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.19.2", 3 | "npmClient": "yarn", 4 | "useWorkspaces": true 5 | } 6 | -------------------------------------------------------------------------------- /media/banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/media/banner.png -------------------------------------------------------------------------------- /media/illustration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/media/illustration.png -------------------------------------------------------------------------------- /media/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/media/screenshot.png -------------------------------------------------------------------------------- /media/showcase/algolia-documentation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/media/showcase/algolia-documentation.png -------------------------------------------------------------------------------- /media/showcase/docsearch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/algolia/autocomplete/de8a1955e67b8df9a7f29f8114e3c579de86bab1/media/showcase/docsearch.png -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish="website" 3 | 4 | [build.environment] 5 | YARN_VERSION = "1.22.5" 6 | -------------------------------------------------------------------------------- /packages/autocomplete-core/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-core 2 | 3 | The [`autocomplete-core`](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-core/createAutocomplete) package is the foundation of Autocomplete. It exposes primitives to build an autocomplete experience. 4 | 5 | You likely don’t need to use this package directly unless you’re building a [renderer](https://www.algolia.com/doc/ui-libraries/autocomplete/guides/creating-a-renderer). 6 | 7 | ## Installation 8 | 9 | ```sh 10 | yarn add @algolia/autocomplete-core 11 | # or 12 | npm install @algolia/autocomplete-core 13 | ``` 14 | 15 | ## Documentation 16 | 17 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-core). 18 | -------------------------------------------------------------------------------- /packages/autocomplete-core/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/__tests__/autoFocus.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '../createAutocomplete'; 2 | 3 | describe('autoFocus', () => { 4 | test('provides the default autoFocus input prop', () => { 5 | const { getInputProps } = createAutocomplete({}); 6 | const inputProps = getInputProps({ inputElement: null }); 7 | 8 | expect(inputProps.autoFocus).toEqual(false); 9 | }); 10 | 11 | test('provides the autoFocus input prop', () => { 12 | const { getInputProps } = createAutocomplete({ autoFocus: true }); 13 | const inputProps = getInputProps({ inputElement: null }); 14 | 15 | expect(inputProps.autoFocus).toEqual(true); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/__tests__/placeholder.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '../createAutocomplete'; 2 | 3 | describe('placeholder', () => { 4 | test('provides the default placeholder input prop', () => { 5 | const { getInputProps } = createAutocomplete({}); 6 | const inputProps = getInputProps({ inputElement: null }); 7 | 8 | expect(inputProps.placeholder).toEqual(''); 9 | }); 10 | 11 | test('provides the user placeholder input prop', () => { 12 | const { getInputProps } = createAutocomplete({ 13 | placeholder: 'My placeholder', 14 | }); 15 | const inputProps = getInputProps({ inputElement: null }); 16 | 17 | expect(inputProps.placeholder).toEqual('My placeholder'); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/__tests__/setIsOpen.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '../createAutocomplete'; 2 | 3 | describe('setIsOpen', () => { 4 | test('sets isOpen', () => { 5 | const onStateChange = jest.fn(); 6 | const { setIsOpen } = createAutocomplete({ onStateChange }); 7 | setIsOpen(true); 8 | 9 | expect(onStateChange).toHaveBeenCalledTimes(1); 10 | expect(onStateChange).toHaveBeenCalledWith( 11 | expect.objectContaining({ 12 | state: expect.objectContaining({ isOpen: true }), 13 | }) 14 | ); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/__tests__/setQuery.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '../createAutocomplete'; 2 | 3 | describe('setQuery', () => { 4 | test('sets the query', () => { 5 | const onStateChange = jest.fn(); 6 | const { setQuery } = createAutocomplete({ onStateChange }); 7 | 8 | setQuery('query'); 9 | 10 | expect(onStateChange).toHaveBeenCalledTimes(1); 11 | expect(onStateChange).toHaveBeenCalledWith( 12 | expect.objectContaining({ 13 | state: expect.objectContaining({ query: 'query' }), 14 | }) 15 | ); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/__tests__/setStatus.test.ts: -------------------------------------------------------------------------------- 1 | import { createAutocomplete } from '../createAutocomplete'; 2 | 3 | describe('setStatus', () => { 4 | test('sets the status', () => { 5 | const onStateChange = jest.fn(); 6 | const { setStatus } = createAutocomplete({ onStateChange }); 7 | 8 | setStatus('stalled'); 9 | 10 | expect(onStateChange).toHaveBeenCalledTimes(1); 11 | expect(onStateChange).toHaveBeenCalledWith( 12 | expect.objectContaining({ 13 | state: expect.objectContaining({ status: 'stalled' }), 14 | }) 15 | ); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/checkOptions.ts: -------------------------------------------------------------------------------- 1 | import { warn } from '@algolia/autocomplete-shared'; 2 | 3 | import { AutocompleteOptions, BaseItem } from './types'; 4 | 5 | export function checkOptions( 6 | options: AutocompleteOptions 7 | ) { 8 | warn( 9 | !options.debug, 10 | 'The `debug` option is meant for development debugging and should not be used in production.' 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/getCompletion.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteState, BaseItem } from './types'; 2 | import { getActiveItem } from './utils'; 3 | 4 | interface GetCompletionProps { 5 | state: AutocompleteState; 6 | } 7 | 8 | export function getCompletion({ 9 | state, 10 | }: GetCompletionProps): string | null { 11 | if (state.isOpen === false || state.activeItemId === null) { 12 | return null; 13 | } 14 | 15 | return getActiveItem(state)?.itemInputValue || null; 16 | } 17 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createAutocomplete'; 2 | export * from './getDefaultProps'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/types/AutocompleteSubscribers.ts: -------------------------------------------------------------------------------- 1 | import { BaseItem, OnActiveParams, OnResolveParams, OnSelectParams } from './'; 2 | 3 | export type AutocompleteSubscriber = { 4 | onSelect(params: OnSelectParams): void; 5 | onActive(params: OnActiveParams): void; 6 | onResolve(params: OnResolveParams): void; 7 | }; 8 | 9 | export type AutocompleteSubscribers = Array< 10 | Partial> 11 | >; 12 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/utils/getAutocompleteElementId.ts: -------------------------------------------------------------------------------- 1 | import type { InternalAutocompleteSource } from '../types'; 2 | 3 | /** 4 | * Returns a full element id for an autocomplete element. 5 | * 6 | * @param autocompleteInstanceId The id of the autocomplete instance 7 | * @param elementId The specific element id 8 | * @param source The source of the element, when it needs to be scoped 9 | */ 10 | export function getAutocompleteElementId( 11 | autocompleteInstanceId: string, 12 | elementId: string, 13 | source?: InternalAutocompleteSource 14 | ) { 15 | return [autocompleteInstanceId, source?.sourceId, elementId] 16 | .filter(Boolean) 17 | .join('-') 18 | .replace(/\s/g, ''); 19 | } 20 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/utils/getNativeEvent.ts: -------------------------------------------------------------------------------- 1 | export function getNativeEvent(event: TEvent) { 2 | return (event as unknown as { nativeEvent: TEvent }).nativeEvent || event; 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createCancelablePromise'; 2 | export * from './createCancelablePromiseList'; 3 | export * from './createConcurrentSafePromise'; 4 | export * from './getNextActiveItemId'; 5 | export * from './getNormalizedSources'; 6 | export * from './getPluginSubmitPromise'; 7 | export * from './getActiveItem'; 8 | export * from './getAutocompleteElementId'; 9 | export * from './isOrContainsNode'; 10 | export * from './isSamsung'; 11 | export * from './mapToAlgoliaResponse'; 12 | export * from './getNativeEvent'; 13 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/utils/isOrContainsNode.ts: -------------------------------------------------------------------------------- 1 | export function isOrContainsNode(parent: Node, child: Node) { 2 | return parent === child || parent.contains(child); 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-core/src/utils/isSamsung.ts: -------------------------------------------------------------------------------- 1 | const regex = /((gt|sm)-|galaxy nexus)|samsung[- ]|samsungbrowser/i; 2 | 3 | export function isSamsung(userAgent: string) { 4 | return Boolean(userAgent && userAgent.match(regex)); 5 | } 6 | -------------------------------------------------------------------------------- /packages/autocomplete-core/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-js 2 | 3 | The [`autocomplete-js`](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete) package is an agnostic virtual DOM renderer. You can use it in JavaScript, Preact, React, or Vue projects. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-js 9 | # or 10 | npm install @algolia/autocomplete-js 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-js/global.d.ts: -------------------------------------------------------------------------------- 1 | declare const __TEST__: boolean; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-js/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getEnvironmentProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getEnvironmentProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getFormProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getFormProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getInputProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getInputProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getItemProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getItemProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getLabelProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getLabelProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getListProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getListProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getPanelProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getPanelProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/__tests__/getRootProps.test.ts: -------------------------------------------------------------------------------- 1 | describe('getRootProps', () => { 2 | test.todo('tests'); 3 | }); 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Highlight'; 2 | export * from './ReverseHighlight'; 3 | export * from './ReverseSnippet'; 4 | export * from './Snippet'; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/elements/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ClearIcon'; 2 | export * from './Input'; 3 | export * from './LoadingIcon'; 4 | export * from './SearchIcon'; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/getCreateDomElement.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteEnvironment } from '@algolia/autocomplete-core'; 2 | 3 | import { setProperties } from './utils'; 4 | 5 | type CreateDomElementProps = Record & { 6 | children?: Node[]; 7 | }; 8 | 9 | export function getCreateDomElement(environment: AutocompleteEnvironment) { 10 | return function createDomElement( 11 | tagName: KParam, 12 | { children = [], ...props }: CreateDomElementProps 13 | ): HTMLElementTagNameMap[KParam] { 14 | const element = environment.document.createElement(tagName); 15 | setProperties(element, props); 16 | element.append(...children); 17 | 18 | return element; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './autocomplete'; 2 | export * from './requesters'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/requesters/createAlgoliaRequester.ts: -------------------------------------------------------------------------------- 1 | import { 2 | createRequester, 3 | fetchAlgoliaResults, 4 | } from '@algolia/autocomplete-preset-algolia'; 5 | 6 | import { userAgents } from '../userAgents'; 7 | 8 | export const createAlgoliaRequester = createRequester( 9 | (params) => 10 | fetchAlgoliaResults({ 11 | ...params, 12 | userAgents, 13 | }), 14 | 'algolia' 15 | ); 16 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/requesters/getAlgoliaFacets.ts: -------------------------------------------------------------------------------- 1 | import { RequestParams } from '@algolia/autocomplete-preset-algolia'; 2 | import { MultipleQueriesQuery } from '@algolia/client-search'; 3 | 4 | import { createAlgoliaRequester } from './createAlgoliaRequester'; 5 | 6 | /** 7 | * Retrieves Algolia facet hits from multiple indices. 8 | */ 9 | export function getAlgoliaFacets(requestParams: RequestParams) { 10 | const requester = createAlgoliaRequester({ 11 | transformResponse: (response) => response.facetHits, 12 | }); 13 | 14 | const queries = requestParams.queries.map((query) => ({ 15 | ...query, 16 | type: 'facet', 17 | })) as MultipleQueriesQuery[]; 18 | 19 | return requester({ 20 | ...requestParams, 21 | queries, 22 | }); 23 | } 24 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/requesters/getAlgoliaResults.ts: -------------------------------------------------------------------------------- 1 | import { createAlgoliaRequester } from './createAlgoliaRequester'; 2 | 3 | /** 4 | * Retrieves Algolia results from multiple indices. 5 | */ 6 | export const getAlgoliaResults = createAlgoliaRequester({ 7 | transformResponse: (response) => response.hits, 8 | }); 9 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/requesters/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getAlgoliaFacets'; 2 | export * from './getAlgoliaResults'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/types/AutocompleteApi.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteScopeApi as AutocompleteCoreScopeApi, 3 | BaseItem, 4 | } from '@algolia/autocomplete-core'; 5 | 6 | import { AutocompleteOptions } from './'; 7 | 8 | export interface AutocompleteApi 9 | extends AutocompleteCoreScopeApi { 10 | /** 11 | * Updates the Autocomplete experience. 12 | */ 13 | update(updatedOptions: Partial>): void; 14 | /** 15 | * Cleans up the DOM mutations and event listeners. 16 | */ 17 | destroy(): void; 18 | } 19 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/types/AutocompleteDom.ts: -------------------------------------------------------------------------------- 1 | export type AutocompleteDom = { 2 | inputWrapper: HTMLDivElement; 3 | input: HTMLInputElement; 4 | root: HTMLDivElement; 5 | form: HTMLFormElement; 6 | label: HTMLLabelElement; 7 | submitButton: HTMLButtonElement; 8 | clearButton: HTMLButtonElement; 9 | loadingIndicator: HTMLDivElement; 10 | panel: HTMLDivElement; 11 | detachedContainer: HTMLDivElement; 12 | detachedOverlay: HTMLDivElement; 13 | detachedSearchButtonQuery: HTMLDivElement; 14 | detachedSearchButtonPlaceholder: HTMLDivElement; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/types/AutocompleteElement.ts: -------------------------------------------------------------------------------- 1 | type WithElementProps = TProps & 2 | Record & { 3 | children?: Node[]; 4 | }; 5 | 6 | export type AutocompleteElement< 7 | TProps = {}, 8 | TElement extends HTMLOrSVGElement = HTMLOrSVGElement 9 | > = (props: WithElementProps) => TElement; 10 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@algolia/autocomplete-shared/dist/esm/js'; 2 | export * from './AutocompleteApi'; 3 | export * from './AutocompleteDom'; 4 | 5 | import { 6 | AutocompleteOptions as AutocompleteCoreOptions, 7 | BaseItem, 8 | } from '@algolia/autocomplete-core'; 9 | import { AutocompleteOptions as AutocompleteJsOptions } from '@algolia/autocomplete-shared/dist/esm/js'; 10 | 11 | export type { 12 | AutocompleteInsightsApi, 13 | AlgoliaInsightsHit, 14 | } from '@algolia/autocomplete-core'; 15 | 16 | export interface AutocompleteOptions 17 | extends AutocompleteJsOptions { 18 | insights?: AutocompleteCoreOptions['insights']; 19 | } 20 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/userAgents.ts: -------------------------------------------------------------------------------- 1 | import { version } from '@algolia/autocomplete-shared'; 2 | 3 | export const userAgents = [{ segment: 'autocomplete-js', version }]; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/utils/__tests__/pickBy.test.ts: -------------------------------------------------------------------------------- 1 | import { pickBy } from '../pickBy'; 2 | 3 | describe('pickBy', () => { 4 | test('picks object properties using the passed predicate', () => { 5 | expect( 6 | pickBy( 7 | { a: true, b: false, cd: true }, 8 | ({ key, value }) => value && key.length === 1 9 | ) 10 | ).toEqual({ 11 | a: true, 12 | }); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/utils/getHTMLElement.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteEnvironment } from '@algolia/autocomplete-core'; 2 | import { invariant } from '@algolia/autocomplete-shared'; 3 | 4 | export function getHTMLElement( 5 | environment: AutocompleteEnvironment, 6 | value: string | HTMLElement 7 | ): HTMLElement { 8 | if (typeof value === 'string') { 9 | const element = environment.document.querySelector(value); 10 | 11 | invariant( 12 | element !== null, 13 | `The element ${JSON.stringify(value)} is not in the document.` 14 | ); 15 | 16 | return element!; 17 | } 18 | 19 | return value; 20 | } 21 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getHTMLElement'; 2 | export * from './mergeClassNames'; 3 | export * from './mergeDeep'; 4 | export * from './pickBy'; 5 | export * from './setProperties'; 6 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/utils/mergeClassNames.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteClassNames } from '../types'; 2 | 3 | export function mergeClassNames( 4 | ...values: Array> 5 | ) { 6 | return values.reduce((acc, current) => { 7 | Object.keys(current).forEach((key) => { 8 | const accValue = acc[key]; 9 | const currentValue = current[key]; 10 | 11 | if (accValue !== currentValue) { 12 | acc[key] = [accValue, currentValue].filter(Boolean).join(' '); 13 | } 14 | }); 15 | 16 | return acc; 17 | }, {}); 18 | } 19 | -------------------------------------------------------------------------------- /packages/autocomplete-js/src/utils/pickBy.ts: -------------------------------------------------------------------------------- 1 | export function pickBy( 2 | obj: Record, 3 | predicate: (value: { key: string; value: TValue }) => boolean 4 | ) { 5 | return Object.entries(obj).reduce>( 6 | (acc, [key, value]) => { 7 | if (predicate({ key, value })) { 8 | return { ...acc, [key]: value }; 9 | } 10 | 11 | return acc; 12 | }, 13 | {} 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /packages/autocomplete-js/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-plugin-algolia-insights 2 | 3 | The Algolia Insights plugin automatically sends click and conversion events to the [Algolia Insights API](https://www.algolia.com/doc/rest-api/insights]) whenever a user interacts with the autocomplete. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-plugin-algolia-insights 9 | # or 10 | npm install @algolia/autocomplete-plugin-algolia-insights 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-algolia-insights). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/createClickedEvent.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | AlgoliaInsightsHit, 3 | ClickedObjectIDsAfterSearchParams, 4 | InsightsParamsWithItems, 5 | } from './types'; 6 | 7 | type CreateClickedEventParams = { 8 | item: AlgoliaInsightsHit; 9 | items: AlgoliaInsightsHit[]; 10 | }; 11 | 12 | export function createClickedEvent({ 13 | item, 14 | items = [], 15 | }: CreateClickedEventParams): Omit< 16 | InsightsParamsWithItems, 17 | 'eventName' 18 | > & { algoliaSource?: string[] } { 19 | return { 20 | index: item.__autocomplete_indexName, 21 | items: [item], 22 | positions: [1 + items.findIndex((x) => x.objectID === item.objectID)], 23 | queryID: item.__autocomplete_queryID, 24 | algoliaSource: ['autocomplete'], 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/index.d.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteInsightsApi } from './types'; 2 | 3 | declare module '@algolia/autocomplete-core' { 4 | export interface AutocompleteContext { 5 | algoliaInsightsPlugin: { 6 | insights: AutocompleteInsightsApi; 7 | }; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './createAlgoliaInsightsPlugin'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/isAlgoliaInsightsHit.ts: -------------------------------------------------------------------------------- 1 | import { AlgoliaInsightsHit } from './types'; 2 | 3 | export function isAlgoliaInsightsHit(hit: any): hit is AlgoliaInsightsHit { 4 | return ( 5 | hit.objectID && hit.__autocomplete_indexName && hit.__autocomplete_queryID 6 | ); 7 | } 8 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/isModernInsightsClient.ts: -------------------------------------------------------------------------------- 1 | import type { InsightsClient } from './types'; 2 | 3 | /** 4 | * Determines if a given insights `client` supports the optional call to `init` 5 | * and the ability to set credentials via extra parameters when sending events. 6 | */ 7 | export function isModernInsightsClient(client: InsightsClient): boolean { 8 | const [major, minor] = (client.version || '').split('.').map(Number); 9 | 10 | /* eslint-disable @typescript-eslint/camelcase */ 11 | const v3 = major >= 3; 12 | const v2_4 = major === 2 && minor >= 4; 13 | const v1_10 = major === 1 && minor >= 10; 14 | 15 | return v3 || v2_4 || v1_10; 16 | /* eslint-enable @typescript-eslint/camelcase */ 17 | } 18 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/types/AlgoliaInsightsHit.ts: -------------------------------------------------------------------------------- 1 | export type AlgoliaInsightsHit = { 2 | objectID: string; 3 | __autocomplete_indexName: string; 4 | __autocomplete_queryID: string; 5 | __autocomplete_algoliaCredentials: { 6 | appId: string; 7 | apiKey: string; 8 | }; 9 | }; 10 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AlgoliaInsightsHit'; 2 | export * from './AutocompleteInsightsApi'; 3 | export * from './EventParams'; 4 | export * from './InsightsClient'; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-algolia-insights/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-plugin-query-suggestions 2 | 3 | The Query Suggestions plugin adds [Query Suggestions](https://www.algolia.com/doc/guides/building-search-ui/ui-and-ux-patterns/query-suggestions/js) to your autocomplete. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-plugin-query-suggestions 9 | # or 10 | npm install @algolia/autocomplete-plugin-query-suggestions 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-query-suggestions). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteSuggestionsPluginTranslations } from './types'; 2 | 3 | export const defaultTranslations: Required = 4 | { 5 | fillQueryTitle: (text: string) => `Fill query with "${text}"`, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createQuerySuggestionsPlugin'; 2 | export * from './getTemplates'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/src/types/Translations.ts: -------------------------------------------------------------------------------- 1 | export type AutocompleteSuggestionsPluginTranslations = { 2 | fillQueryTitle: (text: string) => string; 3 | }; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './QuerySuggestionsHit'; 2 | export * from './Translations'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-query-suggestions/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-plugin-recent-searches 2 | 3 | The Recent Searches plugin displays a list of the latest searches the user made. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-plugin-recent-searches 9 | # or 10 | npm install @algolia/autocomplete-plugin-recent-searches 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-recent-searches). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/addHighlightedAttribute.ts: -------------------------------------------------------------------------------- 1 | import { Highlighted, HistoryItem } from './types'; 2 | 3 | type HighlightParams = { 4 | item: TItem; 5 | query: string; 6 | }; 7 | 8 | export function addHighlightedAttribute({ 9 | item, 10 | query, 11 | }: HighlightParams): Highlighted { 12 | return { 13 | ...item, 14 | _highlightResult: { 15 | label: { 16 | value: query 17 | ? item.label.replace( 18 | new RegExp(query.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'), 'gi'), 19 | (match) => { 20 | return `__aa-highlight__${match}__/aa-highlight__`; 21 | } 22 | ) 23 | : item.label, 24 | }, 25 | }, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/constants.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteRecentSearchesPluginTranslations } from './types'; 2 | 3 | export const LOCAL_STORAGE_KEY = 'AUTOCOMPLETE_RECENT_SEARCHES'; 4 | export const LOCAL_STORAGE_KEY_TEST = 5 | '__AUTOCOMPLETE_RECENT_SEARCHES_PLUGIN_TEST_KEY__'; 6 | 7 | export const defaultTranslations: AutocompleteRecentSearchesPluginTranslations = 8 | { 9 | removeSearchTitle: 'Remove this search', 10 | fillQueryTitle: (text: string) => `Fill query with "${text}"`, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/createStorageApi.ts: -------------------------------------------------------------------------------- 1 | import { HistoryItem, Storage, StorageApi } from './types'; 2 | 3 | export function createStorageApi( 4 | storage: Storage 5 | ): StorageApi { 6 | return { 7 | addItem(item) { 8 | storage.onRemove(item.id); 9 | storage.onAdd(item); 10 | }, 11 | removeItem(id) { 12 | storage.onRemove(id); 13 | }, 14 | getAll(query) { 15 | return storage.getAll(query); 16 | }, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './addHighlightedAttribute'; 2 | export * from './createLocalStorageRecentSearchesPlugin'; 3 | export * from './createRecentSearchesPlugin'; 4 | export * from './getTemplates'; 5 | export * from './search'; 6 | export * from './createLocalStorage'; 7 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/Highlighted.ts: -------------------------------------------------------------------------------- 1 | export type Highlighted = TItem & { 2 | _highlightResult: { 3 | label: { 4 | value: string; 5 | }; 6 | }; 7 | }; 8 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/HistoryItem.ts: -------------------------------------------------------------------------------- 1 | export type HistoryItem = { 2 | id: string; 3 | label: string; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/RecentSearchesItem.ts: -------------------------------------------------------------------------------- 1 | import { HistoryItem } from './HistoryItem'; 2 | 3 | export type RecentSearchesItem = HistoryItem & { 4 | category?: string; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/Storage.ts: -------------------------------------------------------------------------------- 1 | import { MaybePromise } from '@algolia/autocomplete-shared'; 2 | 3 | import { Highlighted } from './Highlighted'; 4 | import { RecentSearchesItem } from './RecentSearchesItem'; 5 | 6 | export type Storage = { 7 | onAdd(item: TItem): void; 8 | onRemove(id: string): void; 9 | getAll(query?: string): MaybePromise>>; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/StorageApi.ts: -------------------------------------------------------------------------------- 1 | import { MaybePromise } from '@algolia/autocomplete-shared'; 2 | 3 | import { Highlighted } from './Highlighted'; 4 | import { RecentSearchesItem } from './RecentSearchesItem'; 5 | 6 | export type StorageApi = { 7 | addItem(item: TItem): void; 8 | removeItem(id: string): void; 9 | getAll(query?: string): MaybePromise>>; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/Translations.ts: -------------------------------------------------------------------------------- 1 | export type AutocompleteRecentSearchesPluginTranslations = { 2 | removeSearchTitle: string; 3 | fillQueryTitle: (text: string) => string; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Highlighted'; 2 | export * from './HistoryItem'; 3 | export * from './RecentSearchesItem'; 4 | export * from './Storage'; 5 | export * from './StorageApi'; 6 | export * from './Translations'; 7 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-recent-searches/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-redirect-url/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-plugin-redirect-url 2 | 3 | The Redirect URL plugin adds redirect functionality to your autocomplete. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-plugin-redirect-url 9 | # or 10 | npm install @algolia/autocomplete-plugin-redirect-url 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-redirect-url). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-redirect-url/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-redirect-url/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createRedirectUrlPlugin'; 2 | export * from './templates'; 3 | export * from './types'; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-redirect-url/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Redirect'; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-redirect-url/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-plugin-tags 2 | 3 | The Tags plugin lets you manage and display a list of tags in your autocomplete. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-plugin-tags 9 | # or 10 | npm install @algolia/autocomplete-plugin-tags 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-tags). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export * from './createTagsPlugin'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/src/types/Tag.ts: -------------------------------------------------------------------------------- 1 | export type DefaultTagType = Record; 2 | 3 | export type BaseTag = TTag & { 4 | label: string; 5 | }; 6 | 7 | export type Tag = 8 | BaseTag & { 9 | remove: () => void; 10 | }; 11 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Tag'; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-plugin-tags/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-preset-algolia 2 | 3 | The Algolia preset provides fetching and highlighting utilities for usage with Algolia. 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-preset-algolia 9 | # or 10 | npm install @algolia/autocomplete-preset-algolia 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-preset-algolia). 16 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { createRollupConfigs } from '../../scripts/rollup/config'; 2 | 3 | import pkg from './package.json'; 4 | 5 | export default createRollupConfigs({ pkg }); 6 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/constants/index.ts: -------------------------------------------------------------------------------- 1 | export const HIGHLIGHT_PRE_TAG = '__aa-highlight__'; 2 | export const HIGHLIGHT_POST_TAG = '__/aa-highlight__'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/HighlightedHit.ts: -------------------------------------------------------------------------------- 1 | import { HighlightResult } from '../types'; 2 | 3 | export type HighlightedHit = THit & { 4 | _highlightResult?: HighlightResult; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/ParseAlgoliaHitParams.ts: -------------------------------------------------------------------------------- 1 | export type ParseAlgoliaHitParams = { 2 | hit: TItem; 3 | attribute: keyof TItem | Array; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/ParsedAttribute.ts: -------------------------------------------------------------------------------- 1 | export type ParsedAttribute = { 2 | value: string; 3 | isHighlighted: boolean; 4 | }; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/SnippetedHit.ts: -------------------------------------------------------------------------------- 1 | import { SnippetResult } from '../types'; 2 | 3 | export type SnippetedHit = THit & { 4 | _snippetResult?: SnippetResult; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/index.ts: -------------------------------------------------------------------------------- 1 | export * from './HighlightedHit'; 2 | export * from './parseAlgoliaHitHighlight'; 3 | export * from './parseAlgoliaHitReverseHighlight'; 4 | export * from './parseAlgoliaHitReverseSnippet'; 5 | export * from './parseAlgoliaHitSnippet'; 6 | export * from './SnippetedHit'; 7 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/parseAlgoliaHitReverseHighlight.ts: -------------------------------------------------------------------------------- 1 | import { HighlightedHit } from './HighlightedHit'; 2 | import { parseAlgoliaHitHighlight } from './parseAlgoliaHitHighlight'; 3 | import { ParseAlgoliaHitParams } from './ParseAlgoliaHitParams'; 4 | import { ParsedAttribute } from './ParsedAttribute'; 5 | import { reverseHighlightedParts } from './reverseHighlightedParts'; 6 | 7 | export function parseAlgoliaHitReverseHighlight< 8 | THit extends HighlightedHit 9 | >(props: ParseAlgoliaHitParams): ParsedAttribute[] { 10 | return reverseHighlightedParts(parseAlgoliaHitHighlight(props)); 11 | } 12 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/parseAlgoliaHitReverseSnippet.ts: -------------------------------------------------------------------------------- 1 | import { ParseAlgoliaHitParams } from './ParseAlgoliaHitParams'; 2 | import { parseAlgoliaHitSnippet } from './parseAlgoliaHitSnippet'; 3 | import { ParsedAttribute } from './ParsedAttribute'; 4 | import { reverseHighlightedParts } from './reverseHighlightedParts'; 5 | import { SnippetedHit } from './SnippetedHit'; 6 | 7 | export function parseAlgoliaHitReverseSnippet< 8 | THit extends SnippetedHit 9 | >(props: ParseAlgoliaHitParams): ParsedAttribute[] { 10 | return reverseHighlightedParts(parseAlgoliaHitSnippet(props)); 11 | } 12 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/highlight/reverseHighlightedParts.ts: -------------------------------------------------------------------------------- 1 | import { isPartHighlighted } from './isPartHighlighted'; 2 | import { ParsedAttribute } from './ParsedAttribute'; 3 | 4 | export function reverseHighlightedParts(parts: ParsedAttribute[]) { 5 | // We don't want to highlight the whole word when no parts match. 6 | if (!parts.some((part) => part.isHighlighted)) { 7 | return parts.map((part) => ({ ...part, isHighlighted: false })); 8 | } 9 | 10 | return parts.map((part, i) => ({ 11 | ...part, 12 | isHighlighted: !isPartHighlighted(parts, i), 13 | })); 14 | } 15 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './highlight'; 2 | export * from './requester'; 3 | export * from './search'; 4 | export * from './types'; 5 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/requester/createAlgoliaRequester.ts: -------------------------------------------------------------------------------- 1 | import { fetchAlgoliaResults } from '../search'; 2 | 3 | import { createRequester } from './createRequester'; 4 | 5 | export const createAlgoliaRequester = createRequester( 6 | fetchAlgoliaResults, 7 | 'algolia' 8 | ); 9 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/requester/getAlgoliaResults.ts: -------------------------------------------------------------------------------- 1 | import { invariant } from '@algolia/autocomplete-shared'; 2 | 3 | import { RequestParams } from '../types'; 4 | 5 | import { createAlgoliaRequester } from './createAlgoliaRequester'; 6 | 7 | /** 8 | * Retrieves Algolia results from multiple indices. 9 | */ 10 | export function getAlgoliaResults(requestParams: RequestParams) { 11 | invariant( 12 | typeof requestParams.searchClient === 'object', 13 | 'The `searchClient` parameter is required for getAlgoliaResults({ searchClient }).' 14 | ); 15 | 16 | const requester = createAlgoliaRequester({ 17 | transformResponse: (response) => response.hits, 18 | }); 19 | 20 | return requester(requestParams); 21 | } 22 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/requester/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createRequester'; 2 | export * from './getAlgoliaFacets'; 3 | export * from './getAlgoliaResults'; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/search/index.ts: -------------------------------------------------------------------------------- 1 | export * from './fetchAlgoliaResults'; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@algolia/autocomplete-shared/dist/esm/preset-algolia/algoliasearch'; 2 | export * from '@algolia/autocomplete-shared/dist/esm/preset-algolia/createRequester'; 3 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/utils/getAppIdAndApiKey.ts: -------------------------------------------------------------------------------- 1 | // typed as any, since it accepts the _real_ js clients, not the interface we otherwise expect 2 | export function getAppIdAndApiKey(searchClient: any): { 3 | appId: string; 4 | apiKey: string; 5 | } { 6 | const transporter = searchClient.transporter || {}; 7 | const headers = transporter.headers || transporter.baseHeaders || {}; 8 | const queryParameters = 9 | transporter.queryParameters || transporter.baseQueryParameters || {}; 10 | const APP_ID = 'x-algolia-application-id'; 11 | const API_KEY = 'x-algolia-api-key'; 12 | const appId = headers[APP_ID] || queryParameters[APP_ID]; 13 | const apiKey = headers[API_KEY] || queryParameters[API_KEY]; 14 | return { appId, apiKey }; 15 | } 16 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './getAppIdAndApiKey'; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-preset-algolia/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/global.d.ts: -------------------------------------------------------------------------------- 1 | declare const __DEV__: boolean; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/MaybePromise.ts: -------------------------------------------------------------------------------- 1 | export type MaybePromise = Promise | TResolution; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/SearchResponse.ts: -------------------------------------------------------------------------------- 1 | import type { SearchResponse as ClientSearchResponse } from '@algolia/client-search'; 2 | 3 | export type SearchResponse = ClientSearchResponse & { 4 | _automaticInsights?: true; 5 | }; 6 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/UserAgent.ts: -------------------------------------------------------------------------------- 1 | export type UserAgent = { segment: string; version?: string }; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/__tests__/createRef.test.ts: -------------------------------------------------------------------------------- 1 | import { createRef } from '../createRef'; 2 | 3 | describe('createRef', () => { 4 | test('stores the value in current', () => { 5 | const ref = createRef(null); 6 | 7 | expect(ref).toEqual({ current: null }); 8 | }); 9 | 10 | test('makes the current value mutable', () => { 11 | const ref = createRef(null); 12 | ref.current = 'updated'; 13 | 14 | expect(ref.current).toEqual('updated'); 15 | }); 16 | }); 17 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/__tests__/decycle.test.ts: -------------------------------------------------------------------------------- 1 | import { decycle } from '../decycle'; 2 | 3 | describe('decycle', () => { 4 | if (__DEV__) { 5 | test('leaves objects with no circular references intact', () => { 6 | const ref = { a: 1 }; 7 | const obj = { 8 | a: 'b', 9 | c: { d: [ref, () => {}, null, false, undefined] }, 10 | }; 11 | 12 | expect(decycle(obj)).toEqual({ 13 | a: 'b', 14 | c: { d: [{ a: 1 }, expect.any(Function), null, false, undefined] }, 15 | }); 16 | }); 17 | test('replaces circular references', () => { 18 | const circular = { a: 'b', self: null }; 19 | circular.self = circular; 20 | 21 | expect(decycle(circular)).toEqual({ a: 'b', self: '[Circular]' }); 22 | }); 23 | } 24 | }); 25 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/__tests__/flatten.test.ts: -------------------------------------------------------------------------------- 1 | import { flatten } from '../flatten'; 2 | 3 | describe('flatten', () => { 4 | it('does not split strings', () => { 5 | expect(flatten(['value', 'value'])).toEqual(['value', 'value']); 6 | }); 7 | 8 | it('spreads single array', () => { 9 | expect(flatten(['value', ['value']])).toEqual(['value', 'value']); 10 | }); 11 | 12 | it('spreads multiple arrays', () => { 13 | expect(flatten([['value'], ['value']])).toEqual(['value', 'value']); 14 | }); 15 | 16 | it('ignores empty arrays', () => { 17 | expect(flatten([[], 'value', 'value'])).toEqual(['value', 'value']); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/__tests__/noop.test.ts: -------------------------------------------------------------------------------- 1 | import { noop } from '../noop'; 2 | 3 | describe('noop', () => { 4 | test('does nothing', () => { 5 | expect(noop).toBeInstanceOf(Function); 6 | expect(noop()).toBeUndefined(); 7 | // Checks that `noop` acts like a function. 8 | expect(noop.toString).toBe(Function.prototype.toString); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/core/AutocompleteCollection.ts: -------------------------------------------------------------------------------- 1 | import { BaseItem } from './AutocompleteApi'; 2 | import { InternalAutocompleteSource } from './AutocompleteSource'; 3 | 4 | export interface AutocompleteCollection { 5 | source: InternalAutocompleteSource; 6 | items: TItem[]; 7 | } 8 | 9 | export interface AutocompleteCollectionItemsArray { 10 | source: InternalAutocompleteSource; 11 | items: TItem[][]; 12 | } 13 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/core/AutocompleteContext.ts: -------------------------------------------------------------------------------- 1 | export interface AutocompleteContext { 2 | [key: string]: unknown; 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/core/AutocompleteState.ts: -------------------------------------------------------------------------------- 1 | import { BaseItem } from './AutocompleteApi'; 2 | import { AutocompleteCollection } from './AutocompleteCollection'; 3 | import { AutocompleteContext } from './AutocompleteContext'; 4 | 5 | export interface AutocompleteState { 6 | activeItemId: number | null; 7 | query: string; 8 | completion: string | null; 9 | collections: Array>; 10 | isOpen: boolean; 11 | status: 'idle' | 'loading' | 'stalled' | 'error'; 12 | context: AutocompleteContext; 13 | } 14 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/core/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AutocompleteApi'; 2 | export * from './AutocompleteCollection'; 3 | export * from './AutocompleteContext'; 4 | export * from './AutocompleteEnvironment'; 5 | export * from './AutocompleteOptions'; 6 | export * from './AutocompleteSource'; 7 | export * from './AutocompletePropGetters'; 8 | export * from './AutocompletePlugin'; 9 | export * from './AutocompleteReshape'; 10 | export * from './AutocompleteSetters'; 11 | export * from './AutocompleteState'; 12 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/createRef.ts: -------------------------------------------------------------------------------- 1 | export function createRef(initialValue: TValue) { 2 | return { 3 | current: initialValue, 4 | }; 5 | } 6 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/debounce.ts: -------------------------------------------------------------------------------- 1 | export function debounce( 2 | fn: (...params: TParams[]) => void, 3 | time: number 4 | ) { 5 | let timerId: ReturnType | undefined = undefined; 6 | 7 | return function (...args: TParams[]) { 8 | if (timerId) { 9 | clearTimeout(timerId); 10 | } 11 | 12 | timerId = setTimeout(() => fn(...args), time); 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/decycle.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Decycles objects with circular references. 3 | * This is used to print cyclic structures in development environment only. 4 | */ 5 | export function decycle(obj: any, seen = new Set()) { 6 | if (!__DEV__ || !obj || typeof obj !== 'object') { 7 | return obj; 8 | } 9 | 10 | if (seen.has(obj)) { 11 | return '[Circular]'; 12 | } 13 | 14 | const newSeen = seen.add(obj); 15 | 16 | if (Array.isArray(obj)) { 17 | return obj.map((x) => decycle(x, newSeen)); 18 | } 19 | 20 | return Object.fromEntries( 21 | Object.entries(obj).map(([key, value]) => [key, decycle(value, newSeen)]) 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/flatten.ts: -------------------------------------------------------------------------------- 1 | export function flatten(values: Array): TType[] { 2 | return values.reduce((a, b) => { 3 | return a.concat(b); 4 | }, []); 5 | } 6 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/generateAutocompleteId.ts: -------------------------------------------------------------------------------- 1 | let autocompleteId = 0; 2 | 3 | export function generateAutocompleteId() { 4 | return `autocomplete-${autocompleteId++}`; 5 | } 6 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/getAttributeValueByPath.ts: -------------------------------------------------------------------------------- 1 | export function getAttributeValueByPath( 2 | record: TRecord, 3 | path: Array 4 | ): any { 5 | return path.reduce((current, key) => current && current[key], record); 6 | } 7 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/getItemsCount.ts: -------------------------------------------------------------------------------- 1 | export function getItemsCount< 2 | TAutocompleteState extends { collections: any[] } 3 | >(state: TAutocompleteState) { 4 | if (state.collections.length === 0) { 5 | return 0; 6 | } 7 | 8 | return state.collections.reduce( 9 | (sum, collection) => sum + collection.items.length, 10 | 0 11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './createRef'; 2 | export * from './debounce'; 3 | export * from './decycle'; 4 | export * from './flatten'; 5 | export * from './generateAutocompleteId'; 6 | export * from './getAttributeValueByPath'; 7 | export * from './getItemsCount'; 8 | export * from './invariant'; 9 | export * from './isEqual'; 10 | export * from './MaybePromise'; 11 | export * from './noop'; 12 | export * from './safelyRunOnBrowser'; 13 | export * from './SearchResponse'; 14 | export * from './UserAgent'; 15 | export * from './userAgents'; 16 | export * from './version'; 17 | export * from './warn'; 18 | export * from './js'; 19 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/invariant.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Throws an error if the condition is not met in development mode. 3 | * This is used to make development a better experience to provide guidance as 4 | * to where the error comes from. 5 | */ 6 | export function invariant( 7 | condition: boolean, 8 | message: string | (() => string) 9 | ) { 10 | if (!__DEV__) { 11 | return; 12 | } 13 | 14 | if (!condition) { 15 | throw new Error( 16 | `[Autocomplete] ${typeof message === 'function' ? message() : message}` 17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/isEqual.ts: -------------------------------------------------------------------------------- 1 | function isPrimitive(obj: any): boolean { 2 | return obj !== Object(obj); 3 | } 4 | 5 | export function isEqual(first: any, second: any): boolean { 6 | if (first === second) { 7 | return true; 8 | } 9 | 10 | if ( 11 | isPrimitive(first) || 12 | isPrimitive(second) || 13 | typeof first === 'function' || 14 | typeof second === 'function' 15 | ) { 16 | return first === second; 17 | } 18 | 19 | if (Object.keys(first).length !== Object.keys(second).length) { 20 | return false; 21 | } 22 | 23 | for (const key of Object.keys(first)) { 24 | if (!(key in second)) { 25 | return false; 26 | } 27 | 28 | if (!isEqual(first[key], second[key])) { 29 | return false; 30 | } 31 | } 32 | 33 | return true; 34 | } 35 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/js/AutocompleteCollection.ts: -------------------------------------------------------------------------------- 1 | import { BaseItem } from '../core'; 2 | 3 | import { InternalAutocompleteSource } from './AutocompleteSource'; 4 | 5 | export interface AutocompleteCollection { 6 | source: InternalAutocompleteSource; 7 | items: TItem[]; 8 | } 9 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/js/AutocompleteState.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteState as AutocompleteCoreState, BaseItem } from '../core'; 2 | 3 | import { AutocompleteCollection } from './AutocompleteCollection'; 4 | 5 | export type AutocompleteState = Omit< 6 | AutocompleteCoreState, 7 | 'collections' 8 | > & { 9 | /** 10 | * The collections of items. 11 | * 12 | * @link https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/state/#param-collections 13 | */ 14 | collections: Array>; 15 | }; 16 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/js/AutocompleteTranslations.ts: -------------------------------------------------------------------------------- 1 | export type AutocompleteTranslations = { 2 | detachedCancelButtonText: string; 3 | clearButtonTitle: string; 4 | submitButtonTitle: string; 5 | detachedSearchButtonTitle: string; 6 | }; 7 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/js/HighlightHitParams.ts: -------------------------------------------------------------------------------- 1 | export type HighlightHitParams = { 2 | /** 3 | * The Algolia hit whose attribute to retrieve the highlighted parts from. 4 | */ 5 | hit: THit; 6 | /** 7 | * The attribute to retrieve the highlighted parts from. 8 | * 9 | * You can use the array syntax to reference nested attributes. 10 | */ 11 | attribute: keyof THit | Array; 12 | /** 13 | * The tag name to use for highlighted parts. 14 | * 15 | * @default "mark" 16 | */ 17 | tagName?: string; 18 | }; 19 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/js/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AutocompleteClassNames'; 2 | export * from './AutocompleteCollection'; 3 | export * from './AutocompleteComponents'; 4 | export * from './AutocompleteOptions'; 5 | export * from './AutocompletePlugin'; 6 | export * from './AutocompletePropGetters'; 7 | export * from './AutocompleteRender'; 8 | export * from './AutocompleteRenderer'; 9 | export * from './AutocompleteSource'; 10 | export * from './AutocompleteState'; 11 | export * from './AutocompleteTranslations'; 12 | export * from './HighlightHitParams'; 13 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/noop.ts: -------------------------------------------------------------------------------- 1 | export const noop = () => {}; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/safelyRunOnBrowser.ts: -------------------------------------------------------------------------------- 1 | type BrowserCallback = (params: { window: typeof window }) => TReturn; 2 | 3 | /** 4 | * Safely runs code meant for browser environments only. 5 | */ 6 | export function safelyRunOnBrowser( 7 | callback: BrowserCallback 8 | ): TReturn | undefined { 9 | if (typeof window !== 'undefined') { 10 | return callback({ window }); 11 | } 12 | 13 | return undefined; 14 | } 15 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/userAgents.ts: -------------------------------------------------------------------------------- 1 | import { version } from './version'; 2 | 3 | export const userAgents = [{ segment: 'autocomplete-core', version }]; 4 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/version.ts: -------------------------------------------------------------------------------- 1 | export const version = '1.19.2'; 2 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/src/warn.ts: -------------------------------------------------------------------------------- 1 | export const warnCache = { 2 | current: {}, 3 | }; 4 | 5 | /** 6 | * Logs a warning if the condition is not met. 7 | * This is used to log issues in development environment only. 8 | */ 9 | export function warn(condition: boolean, message: string) { 10 | if (!__DEV__) { 11 | return; 12 | } 13 | 14 | if (condition) { 15 | return; 16 | } 17 | 18 | const sanitizedMessage = message.trim(); 19 | const hasAlreadyPrinted = warnCache.current[sanitizedMessage]; 20 | 21 | if (!hasAlreadyPrinted) { 22 | warnCache.current[sanitizedMessage] = true; 23 | 24 | // eslint-disable-next-line no-console 25 | console.warn(`[Autocomplete] ${sanitizedMessage}`); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/autocomplete-shared/tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.declaration" 3 | } 4 | -------------------------------------------------------------------------------- /packages/autocomplete-theme-classic/README.md: -------------------------------------------------------------------------------- 1 | # @algolia/autocomplete-theme-classic 2 | 3 | The theme is designed as a neutral and clean starter. You can use it as a base and customize it with [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties). 4 | 5 | ## Installation 6 | 7 | ```sh 8 | yarn add @algolia/autocomplete-theme-classic 9 | # or 10 | npm install @algolia/autocomplete-theme-classic 11 | ``` 12 | 13 | ## Documentation 14 | 15 | See [**Documentation**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-theme-classic). 16 | -------------------------------------------------------------------------------- /postcss.config.mjs: -------------------------------------------------------------------------------- 1 | import sass from '@csstools/postcss-sass'; 2 | import autoprefixer from 'autoprefixer'; 3 | import cssnano from 'cssnano'; 4 | import color from 'postcss-color-rgb'; 5 | import parser from 'postcss-scss'; 6 | import presetEnv from 'postcss-preset-env'; 7 | 8 | const MINIFIED = process.env.MINIFIED; 9 | const plugins = [ 10 | presetEnv({ 11 | features: { 12 | 'nesting-rules': false, 13 | }, 14 | }), 15 | color, 16 | sass, 17 | autoprefixer, 18 | ]; 19 | 20 | export default { 21 | parser, 22 | plugins: MINIFIED ? [...plugins, cssnano] : plugins, 23 | }; 24 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:js-lib", 4 | "schedule:monthly", 5 | ":semanticCommitTypeAll(chore)" 6 | ], 7 | "timezone": "Europe/Paris", 8 | "packageRules": [ 9 | { 10 | "packagePatterns": ["^@types"], 11 | "depTypeList": ["devDependencies"], 12 | "rangeStrategy": "replace" 13 | }, 14 | { 15 | "matchUpdateTypes": ["minor", "patch"], 16 | "matchCurrentVersion": "!/^0/", 17 | "automerge": true, 18 | "automergeType": "branch" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /scripts/babel/__tests__/wrap-warning-with-dev-check.test.js: -------------------------------------------------------------------------------- 1 | import { transformSync } from '@babel/core'; 2 | 3 | import wrapWarningWithDevCheck from '../wrap-warning-with-dev-check'; 4 | 5 | function babelTransform(code) { 6 | return transformSync(code, { 7 | configFile: false, 8 | plugins: [wrapWarningWithDevCheck], 9 | }).code; 10 | } 11 | 12 | describe('wrap-warning-with-dev-check', () => { 13 | test('should wrap warning calls', () => { 14 | expect(babelTransform("warn(condition, 'message');")).toEqual( 15 | "__DEV__ ? warn(condition, 'message') : void 0;" 16 | ); 17 | }); 18 | 19 | test('should not wrap other calls', () => { 20 | expect(babelTransform("deprecate(fn, 'message');")).toEqual( 21 | "deprecate(fn, 'message');" 22 | ); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /scripts/getBundleBanner.mjs: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | 3 | export function getBundleBanner(pkg) { 4 | const lastCommitHash = execSync('git rev-parse --short HEAD') 5 | .toString() 6 | .trim(); 7 | const version = process.env.SHIPJS 8 | ? pkg.version 9 | : `${pkg.version} (UNRELEASED ${lastCommitHash})`; 10 | const authors = '© Algolia, Inc. and contributors'; 11 | 12 | return `/*! ${pkg.name} ${version} | MIT License | ${authors} | ${pkg.homepage} */`; 13 | } 14 | -------------------------------------------------------------------------------- /scripts/jest/matchers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './toWarnDev'; 2 | -------------------------------------------------------------------------------- /scripts/jest/matchers/toWarnDev.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/generic-type-naming */ 2 | 3 | declare namespace jest { 4 | interface Matchers { 5 | /** 6 | * Ensures that a warning is triggered when the callback is called. 7 | */ 8 | toWarnDev(expectedMessage?: string): CustomMatcherResult; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /scripts/jest/setupTests.ts: -------------------------------------------------------------------------------- 1 | import { createMatchMedia } from '../../test/utils'; 2 | 3 | import { toWarnDev } from './matchers'; 4 | 5 | expect.extend({ toWarnDev }); 6 | 7 | global.console.warn = jest.fn(); 8 | 9 | Object.defineProperty(window, 'matchMedia', { 10 | writable: true, 11 | value: createMatchMedia({}), 12 | }); 13 | -------------------------------------------------------------------------------- /test/utils/castToJestMock.ts: -------------------------------------------------------------------------------- 1 | export const castToJestMock = any>( 2 | func: TFunction 3 | ) => func as jest.MockedFunction; 4 | -------------------------------------------------------------------------------- /test/utils/createCollection.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteCollection } from '@algolia/autocomplete-core'; 2 | 3 | import { createSource } from './createSource'; 4 | 5 | type CreateCollectionParams> = Partial<{ 6 | source: Partial['source']>; 7 | items: AutocompleteCollection['items']; 8 | }>; 9 | 10 | export function createCollection>({ 11 | source, 12 | items = [], 13 | }: CreateCollectionParams): AutocompleteCollection { 14 | return { 15 | source: createSource(source), 16 | items, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /test/utils/createMatchMedia.ts: -------------------------------------------------------------------------------- 1 | type MatchMediaProps = Partial<{ 2 | matches: boolean; 3 | media: string; 4 | onchange: null; 5 | addListener: jest.Mock; 6 | removeListener: jest.Mock; 7 | addEventListener: jest.Mock; 8 | removeEventListener: jest.Mock; 9 | dispatchEvent: jest.Mock; 10 | }>; 11 | 12 | export const createMatchMedia = (props: MatchMediaProps) => { 13 | return jest.fn((query) => ({ 14 | matches: false, 15 | media: query, 16 | onchange: null, 17 | addListener: jest.fn(), 18 | removeListener: jest.fn(), 19 | addEventListener: jest.fn(), 20 | removeEventListener: jest.fn(), 21 | dispatchEvent: jest.fn(), 22 | ...props, 23 | })); 24 | }; 25 | -------------------------------------------------------------------------------- /test/utils/createNavigator.ts: -------------------------------------------------------------------------------- 1 | type AutocompleteNavigator = { 2 | navigate(...args: any[]): void; 3 | navigateNewTab(...args: any[]): void; 4 | navigateNewWindow(...args: any[]): void; 5 | }; 6 | 7 | export function createNavigator( 8 | navigator?: Partial 9 | ): AutocompleteNavigator { 10 | return { 11 | navigate: jest.fn(), 12 | navigateNewTab: jest.fn(), 13 | navigateNewWindow: jest.fn(), 14 | ...navigator, 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /test/utils/createScopeApi.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteScopeApi, BaseItem } from '@algolia/autocomplete-core'; 2 | 3 | export function createScopeApi< 4 | TItem extends BaseItem 5 | >(): AutocompleteScopeApi { 6 | return { 7 | setActiveItemId: jest.fn(), 8 | setQuery: jest.fn(), 9 | setCollections: jest.fn(), 10 | setIsOpen: jest.fn(), 11 | setStatus: jest.fn(), 12 | setContext: jest.fn(), 13 | navigator: { 14 | navigate: jest.fn(), 15 | navigateNewTab: jest.fn(), 16 | navigateNewWindow: jest.fn(), 17 | }, 18 | refresh: jest.fn(), 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /test/utils/createSource.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AutocompleteSource, 3 | BaseItem, 4 | InternalAutocompleteSource, 5 | } from '@algolia/autocomplete-core'; 6 | 7 | export function createSource( 8 | source?: Partial> 9 | ): InternalAutocompleteSource { 10 | return { 11 | sourceId: 'testSource', 12 | getItemInputValue: ({ state }) => state.query, 13 | getItemUrl: () => undefined, 14 | onActive: () => {}, 15 | onSelect: () => {}, 16 | onResolve: () => {}, 17 | getItems: () => [], 18 | ...source, 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /test/utils/createState.ts: -------------------------------------------------------------------------------- 1 | import { AutocompleteState } from '@algolia/autocomplete-core'; 2 | import { BaseItem } from '@algolia/autocomplete-core/src'; 3 | 4 | export function createState( 5 | partialState: Partial> = {} 6 | ): AutocompleteState { 7 | return { 8 | activeItemId: null, 9 | query: '', 10 | completion: null, 11 | collections: [], 12 | isOpen: false, 13 | status: 'idle', 14 | context: {}, 15 | ...partialState, 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /test/utils/defer.ts: -------------------------------------------------------------------------------- 1 | export function defer(fn: () => TValue, timeout: number) { 2 | return new Promise((resolve) => { 3 | setTimeout(() => resolve(fn()), timeout); 4 | }); 5 | } 6 | -------------------------------------------------------------------------------- /test/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './castToJestMock'; 2 | export * from './createApiResponse'; 3 | export * from './createCollection'; 4 | export * from './createMatchMedia'; 5 | export * from './createNavigator'; 6 | export * from './createPlayground'; 7 | export * from './createScopeApi'; 8 | export * from './createSearchClient'; 9 | export * from './createSource'; 10 | export * from './createState'; 11 | export * from './defer'; 12 | export * from './runAllMicroTasks'; 13 | -------------------------------------------------------------------------------- /test/utils/runAllMicroTasks.ts: -------------------------------------------------------------------------------- 1 | export function runAllMicroTasks(): Promise { 2 | return new Promise(setImmediate); 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.declaration.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig", 3 | "compilerOptions": { 4 | "declaration": true, 5 | "emitDeclarationOnly": true, 6 | "noEmit": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowSyntheticDefaultImports": true, 4 | "jsx": "react-jsx", 5 | "jsxImportSource": "preact", 6 | "module": "es2015", 7 | "moduleResolution": "node", 8 | "noFallthroughCasesInSwitch": true, 9 | "noImplicitAny": false, 10 | "noImplicitReturns": true, 11 | "noUnusedLocals": false, 12 | "noUnusedParameters": false, 13 | "resolveJsonModule": true, 14 | "skipLibCheck": true, 15 | "strict": true, 16 | "target": "ESNEXT" 17 | }, 18 | "exclude": [ 19 | ".storybook", 20 | "**/__fixtures__/**/*", 21 | "**/__mocks__/**/*", 22 | "**/__tests__/**/*", 23 | "**/dist", 24 | "**/node_modules", 25 | "stories", 26 | "examples" 27 | ] 28 | } 29 | --------------------------------------------------------------------------------