diff --git a/bundlesize.config.json b/bundlesize.config.json index 27930d0b2..e68963f03 100644 --- a/bundlesize.config.json +++ b/bundlesize.config.json @@ -6,7 +6,7 @@ }, { "path": "packages/autocomplete-js/dist/umd/index.production.js", - "maxSize": "14.50 kB" + "maxSize": "14.75 kB" }, { "path": "packages/autocomplete-preset-algolia/dist/umd/index.production.js", diff --git a/cypress/test-apps/js/app.tsx b/cypress/test-apps/js/app.tsx index 933500982..bc62235d5 100644 --- a/cypress/test-apps/js/app.tsx +++ b/cypress/test-apps/js/app.tsx @@ -1,8 +1,8 @@ /** @jsx h */ import { autocomplete, + AutocompleteComponents, getAlgoliaHits, - snippetHit, } from '@algolia/autocomplete-js'; import { AutocompleteInsightsApi, @@ -102,10 +102,11 @@ autocomplete({ ); }, - item({ item }) { + item({ item, components }) { return ( ); @@ -124,9 +125,10 @@ autocomplete({ type ProductItemProps = { hit: ProductHit; insights: AutocompleteInsightsApi; + components: AutocompleteComponents; }; -function ProductItem({ hit, insights }: ProductItemProps) { +function ProductItem({ hit, insights, components }: ProductItemProps) { return (
@@ -134,10 +136,10 @@ function ProductItem({ hit, insights }: ProductItemProps) {
- {snippetHit({ hit, attribute: 'name' })} +
- {snippetHit({ hit, attribute: 'description' })} +
diff --git a/cypress/test-apps/js/categoriesPlugin.tsx b/cypress/test-apps/js/categoriesPlugin.tsx index 57075aaf5..9e3bc3975 100644 --- a/cypress/test-apps/js/categoriesPlugin.tsx +++ b/cypress/test-apps/js/categoriesPlugin.tsx @@ -2,7 +2,6 @@ import { AutocompletePlugin, getAlgoliaFacetHits, - highlightHit, } from '@algolia/autocomplete-js'; import { SearchClient } from 'algoliasearch/lite'; import { h, Fragment } from 'preact'; @@ -52,7 +51,7 @@ export function createCategoriesPlugin({ ); }, - item({ item }) { + item({ item, components }) { return (
@@ -73,10 +72,7 @@ export function createCategoriesPlugin({
- {highlightHit({ - hit: item, - attribute: 'label', - })} +
diff --git a/cypress/test-apps/js/env.ts b/cypress/test-apps/js/env.ts index 35fed015b..6eef24529 100644 --- a/cypress/test-apps/js/env.ts +++ b/cypress/test-apps/js/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/playground/app.tsx b/examples/playground/app.tsx index 25c4a7bdb..7a28a1908 100644 --- a/examples/playground/app.tsx +++ b/examples/playground/app.tsx @@ -1,8 +1,8 @@ /** @jsx h */ import { autocomplete, + AutocompleteComponents, getAlgoliaHits, - snippetHit, } from '@algolia/autocomplete-js'; import { AutocompleteInsightsApi, @@ -93,10 +93,11 @@ autocomplete({ ); }, - item({ item }) { + item({ item, components }) { return ( ); @@ -115,9 +116,10 @@ autocomplete({ type ProductItemProps = { hit: ProductHit; insights: AutocompleteInsightsApi; + components: AutocompleteComponents; }; -function ProductItem({ hit, insights }: ProductItemProps) { +function ProductItem({ hit, insights, components }: ProductItemProps) { return (
@@ -125,10 +127,10 @@ function ProductItem({ hit, insights }: ProductItemProps) {
- {snippetHit({ hit, attribute: 'name' })} +
- {snippetHit({ hit, attribute: 'description' })} +
diff --git a/examples/playground/categoriesPlugin.tsx b/examples/playground/categoriesPlugin.tsx index 4f11e9c14..0131e2678 100644 --- a/examples/playground/categoriesPlugin.tsx +++ b/examples/playground/categoriesPlugin.tsx @@ -2,7 +2,6 @@ import { AutocompletePlugin, getAlgoliaFacetHits, - highlightHit, } from '@algolia/autocomplete-js'; import { SearchClient } from 'algoliasearch/lite'; import { h, Fragment } from 'preact'; @@ -56,7 +55,7 @@ export function createCategoriesPlugin({ ); }, - item({ item }) { + item({ item, components }) { return (
@@ -77,10 +76,7 @@ export function createCategoriesPlugin({
- {highlightHit({ - hit: item, - attribute: 'label', - })} +
diff --git a/examples/playground/env.ts b/examples/playground/env.ts index 35fed015b..6eef24529 100644 --- a/examples/playground/env.ts +++ b/examples/playground/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/query-suggestions-with-categories/env.ts b/examples/query-suggestions-with-categories/env.ts index 35fed015b..6eef24529 100644 --- a/examples/query-suggestions-with-categories/env.ts +++ b/examples/query-suggestions-with-categories/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/query-suggestions-with-hits/app.tsx b/examples/query-suggestions-with-hits/app.tsx index dc6af54f0..1f143e6c0 100644 --- a/examples/query-suggestions-with-hits/app.tsx +++ b/examples/query-suggestions-with-hits/app.tsx @@ -1,8 +1,8 @@ /** @jsx h */ import { autocomplete, + AutocompleteComponents, getAlgoliaHits, - snippetHit, } from '@algolia/autocomplete-js'; import { AutocompleteInsightsApi, @@ -85,10 +85,11 @@ autocomplete({ ); }, - item({ item }) { + item({ item, components }) { return ( ); @@ -107,9 +108,10 @@ autocomplete({ type ProductItemProps = { hit: ProductHit; insights: AutocompleteInsightsApi; + components: AutocompleteComponents; }; -function ProductItem({ hit, insights }: ProductItemProps) { +function ProductItem({ hit, insights, components }: ProductItemProps) { return (
@@ -117,7 +119,7 @@ function ProductItem({ hit, insights }: ProductItemProps) {
- {snippetHit({ hit, attribute: 'name' })} +
From {hit.brand} in{' '} diff --git a/examples/query-suggestions-with-hits/env.ts b/examples/query-suggestions-with-hits/env.ts index 35fed015b..6eef24529 100644 --- a/examples/query-suggestions-with-hits/env.ts +++ b/examples/query-suggestions-with-hits/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/query-suggestions-with-inline-categories/app.tsx b/examples/query-suggestions-with-inline-categories/app.tsx index 830d6afd0..c436b9af4 100644 --- a/examples/query-suggestions-with-inline-categories/app.tsx +++ b/examples/query-suggestions-with-inline-categories/app.tsx @@ -1,5 +1,5 @@ /** @jsx h */ -import { autocomplete, reverseHighlightHit } from '@algolia/autocomplete-js'; +import { autocomplete } from '@algolia/autocomplete-js'; import { createQuerySuggestionsPlugin } from '@algolia/autocomplete-plugin-query-suggestions'; import algoliasearch from 'algoliasearch'; import { h, Fragment } from 'preact'; @@ -30,7 +30,7 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({ ...source, templates: { ...source.templates, - item({ item, createElement }) { + item({ item, components }) { return (
@@ -46,11 +46,7 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({
- {reverseHighlightHit({ - hit: item, - attribute: 'query', - createElement, - })} +
{item.__autocomplete_qsCategory && ( @@ -73,6 +69,7 @@ const querySuggestionsPlugin = createQuerySuggestionsPlugin({ className="aa-ItemActionButton" title={`Fill query with "${item.query}"`} onClick={(event) => { + event.preventDefault(); event.stopPropagation(); onTapAhead(item); }} diff --git a/examples/query-suggestions-with-inline-categories/env.ts b/examples/query-suggestions-with-inline-categories/env.ts index 35fed015b..6eef24529 100644 --- a/examples/query-suggestions-with-inline-categories/env.ts +++ b/examples/query-suggestions-with-inline-categories/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/query-suggestions-with-recent-searches/env.ts b/examples/query-suggestions-with-recent-searches/env.ts index 35fed015b..6eef24529 100644 --- a/examples/query-suggestions-with-recent-searches/env.ts +++ b/examples/query-suggestions-with-recent-searches/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/query-suggestions/env.ts b/examples/query-suggestions/env.ts index 35fed015b..6eef24529 100644 --- a/examples/query-suggestions/env.ts +++ b/examples/query-suggestions/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/recently-viewed-items/app.tsx b/examples/recently-viewed-items/app.tsx index 8b9a4d1c5..fe75ecb20 100644 --- a/examples/recently-viewed-items/app.tsx +++ b/examples/recently-viewed-items/app.tsx @@ -1,8 +1,8 @@ /** @jsx h */ import { autocomplete, + AutocompleteComponents, getAlgoliaHits, - highlightHit, } from '@algolia/autocomplete-js'; import algoliasearch from 'algoliasearch'; import { h, Fragment } from 'preact'; @@ -66,8 +66,10 @@ autocomplete({ ); }, - item({ item }) { - return ; + item({ item, components }) { + return ( + + ); }, noResults() { return ( @@ -82,9 +84,10 @@ autocomplete({ type ProductItemProps = { hit: ProductHit; + components: AutocompleteComponents; }; -function AutocompleteProductItem({ hit }: ProductItemProps) { +function AutocompleteProductItem({ hit, components }: ProductItemProps) { return (
@@ -92,7 +95,7 @@ function AutocompleteProductItem({ hit }: ProductItemProps) {
- {highlightHit({ hit, attribute: 'name' })} +
diff --git a/examples/recently-viewed-items/env.ts b/examples/recently-viewed-items/env.ts index 35fed015b..6eef24529 100644 --- a/examples/recently-viewed-items/env.ts +++ b/examples/recently-viewed-items/env.ts @@ -1,9 +1,10 @@ -import { h } from 'preact'; +import * as preact from 'preact'; // Parcel picks the `source` field of the monorepo packages and thus doesn't -// apply the Babel config to replace our `__DEV__` global expression. -// We therefore need to manually override it in the example app. +// apply the Babel config. We therefore need to manually override the constants +// in the app, as well as the React pragmas. // See https://twitter.com/devongovett/status/1134231234605830144 (global as any).__DEV__ = process.env.NODE_ENV !== 'production'; (global as any).__TEST__ = false; -(global as any).h = h; +(global as any).h = preact.h; +(global as any).React = preact; diff --git a/examples/recently-viewed-items/recentlyViewedItemsPlugin.tsx b/examples/recently-viewed-items/recentlyViewedItemsPlugin.tsx index 4c64a2093..623081067 100644 --- a/examples/recently-viewed-items/recentlyViewedItemsPlugin.tsx +++ b/examples/recently-viewed-items/recentlyViewedItemsPlugin.tsx @@ -1,5 +1,5 @@ /** @jsx h */ -import { AutocompletePlugin, highlightHit } from '@algolia/autocomplete-js'; +import { AutocompletePlugin } from '@algolia/autocomplete-js'; import { createLocalStorageRecentSearchesPlugin, search, @@ -72,7 +72,7 @@ export function createLocalStorageRecentlyViewedItems< ); }, - item({ item, createElement }) { + item({ item, components }) { return ( {item.image ? ( @@ -94,11 +94,7 @@ export function createLocalStorageRecentlyViewedItems<
- {highlightHit({ - hit: item, - attribute: 'label', - createElement, - })} +
@@ -106,6 +102,7 @@ export function createLocalStorageRecentlyViewedItems< className="aa-ItemActionButton" title="Remove this search" onClick={(event) => { + event.preventDefault(); event.stopPropagation(); onRemove(item.id); }} diff --git a/packages/autocomplete-js/src/__tests__/components.test.tsx b/packages/autocomplete-js/src/__tests__/components.test.tsx new file mode 100644 index 000000000..18724bd51 --- /dev/null +++ b/packages/autocomplete-js/src/__tests__/components.test.tsx @@ -0,0 +1,430 @@ +/** @jsx h */ +import { Hit } from '@algolia/client-search'; +import { fireEvent, waitFor } from '@testing-library/dom'; +import { h } from 'preact'; + +import { createSource } from '../../../../test/utils'; +import { autocomplete } from '../autocomplete'; + +import products from './fixtures/products.json'; + +type ProductRecord = { + brand: string; + categories: string[]; + description: string; + free_shipping: boolean; + hierarchicalCategories: { + lvl0: string; + lvl1?: string; + lvl2?: string; + lvl3?: string; + lvl4?: string; + lvl5?: string; + lvl6?: string; + }; + image: string; + name: string; + popularity: number; + price: number; + prince_range: string; + rating: number; + type: string; +}; +type ProductHit = Hit; + +const productHits = products.results[0].hits; + +describe('components', () => { + afterEach(() => { + document.body.innerHTML = ''; + }); + + test('provides Highlight component', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ; + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test('provides Highlight component that accepts tagName', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test.todo('provides Highlight component with custom createElement'); + + test('provides Snippet component', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ; + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test('provides Snippet component that accepts tagName', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test.todo('provides Snippet component with custom createElement'); + + test('provides ReverseHighlight component', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test('provides ReverseHighlight component that accepts tagName', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test.todo('provides ReverseHighlight component with custom createElement'); + + test('provides ReverseSnippet component', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test('provides ReverseSnippet component that accepts tagName', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); + + test.todo('provides ReverseSnippet component with custom createElement'); + + test('allows registering custom components', async () => { + const container = document.createElement('div'); + const panelContainer = document.createElement('div'); + + function CustomComponent({ children }) { + return children; + } + + document.body.appendChild(panelContainer); + autocomplete({ + container, + panelContainer, + components: { + CustomComponent, + }, + getSources() { + return [ + { + ...createSource({ + getItems() { + return productHits; + }, + }), + templates: { + item({ item, components }) { + return ( + + {item.name} + + ); + }, + }, + }, + ]; + }, + }); + + const input = container.querySelector('.aa-Input'); + fireEvent.input(input, { target: { value: 'a' } }); + + await waitFor(() => { + expect( + panelContainer.querySelector('.aa-Item').innerHTML + ).toMatchInlineSnapshot( + `"Apple - iPhone SE 16GB - Space Gray (Verizon)"` + ); + }); + }); +}); diff --git a/packages/autocomplete-js/src/__tests__/fixtures/products.json b/packages/autocomplete-js/src/__tests__/fixtures/products.json new file mode 100644 index 000000000..29f575a21 --- /dev/null +++ b/packages/autocomplete-js/src/__tests__/fixtures/products.json @@ -0,0 +1,387 @@ +{ + "results": [ + { + "hits": [ + { + "name": "Apple - iPhone SE 16GB - Space Gray (Verizon)", + "description": "iPhone SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "brand": "Apple", + "categories": ["Cell Phones", "iPhone", "iPhone SE"], + "hierarchicalCategories": { + "lvl0": "Cell Phones", + "lvl1": "Cell Phones > iPhone", + "lvl2": "Cell Phones > iPhone > iPhone SE" + }, + "type": "Vzw iphone handset", + "price": 449.99, + "price_range": "200 - 500", + "image": "https://cdn-demo.algolia.com/bestbuy-0118/5005506_sb.jpg", + "url": "https://api.bestbuy.com/click/-/5005506/pdp", + "free_shipping": true, + "rating": 4, + "popularity": 19581, + "objectID": "5005506", + "_snippetResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Space Gray (Verizon)", + "matchLevel": "full" + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos …", + "matchLevel": "full" + } + }, + "_highlightResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Space Gray (Verizon)", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "brand": { + "value": "Apple", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Cell Phones", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__", + "matchLevel": "full", + "fullyHighlighted": true, + "matchedWords": ["iphone"] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + ], + "type": { + "value": "Vzw __aa-highlight__iphone__/aa-highlight__ handset", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + } + }, + { + "name": "Apple - iPhone SE 64GB - Space Gray (AT&T)", + "description": "iPhone SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "brand": "Apple", + "categories": ["Cell Phones", "iPhone", "iPhone SE"], + "hierarchicalCategories": { + "lvl0": "Cell Phones", + "lvl1": "Cell Phones > iPhone", + "lvl2": "Cell Phones > iPhone > iPhone SE" + }, + "type": "At&t iphone handset", + "price": 499.99, + "price_range": "200 - 500", + "image": "https://cdn-demo.algolia.com/bestbuy-0118/5005675_sb.jpg", + "url": "https://api.bestbuy.com/click/-/5005675/pdp", + "free_shipping": true, + "rating": 4, + "popularity": 19311, + "objectID": "5005675", + "_snippetResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 64GB - Space Gray (AT&T)", + "matchLevel": "full" + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos …", + "matchLevel": "full" + } + }, + "_highlightResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 64GB - Space Gray (AT&T)", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "brand": { + "value": "Apple", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Cell Phones", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__", + "matchLevel": "full", + "fullyHighlighted": true, + "matchedWords": ["iphone"] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + ], + "type": { + "value": "At&t __aa-highlight__iphone__/aa-highlight__ handset", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + } + }, + { + "name": "Apple - iPhone SE 16GB - Space Gray (Sprint)", + "description": "iPhone SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "brand": "Apple", + "categories": ["Cell Phones", "iPhone", "iPhone SE"], + "hierarchicalCategories": { + "lvl0": "Cell Phones", + "lvl1": "Cell Phones > iPhone", + "lvl2": "Cell Phones > iPhone > iPhone SE" + }, + "type": "Spr iphone handset", + "price": 449.99, + "price_range": "200 - 500", + "image": "https://cdn-demo.algolia.com/bestbuy-0118/5005532_sb.jpg", + "url": "https://api.bestbuy.com/click/-/5005532/pdp", + "free_shipping": true, + "rating": 4, + "popularity": 19206, + "objectID": "5005532", + "_snippetResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Space Gray (Sprint)", + "matchLevel": "full" + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos …", + "matchLevel": "full" + } + }, + "_highlightResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Space Gray (Sprint)", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "brand": { + "value": "Apple", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Cell Phones", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__", + "matchLevel": "full", + "fullyHighlighted": true, + "matchedWords": ["iphone"] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + ], + "type": { + "value": "Spr __aa-highlight__iphone__/aa-highlight__ handset", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + } + }, + { + "name": "Apple - iPhone 6s 32GB - Space Gray (AT&T)", + "description": "A 4.7-inch Retina HD display with 3D Touch. 7000 series aluminum and stronger cover glass. An A9 chip with 64-bit desktop-class architecture. All new 12MP iSight camera with Live Photos. Touch ID. Faster LTE and Wi-Fi. Long battery life and iOS 10 and iCloud. All in a smooth, continuous unibody design.", + "brand": "Apple", + "categories": ["Cell Phones", "iPhone"], + "hierarchicalCategories": { + "lvl0": "Cell Phones", + "lvl1": "Cell Phones > iPhone" + }, + "type": "Att iph unv handset", + "price": 599.99, + "price_range": "500 - 2000", + "image": "https://cdn-demo.algolia.com/bestbuy-0118/5580377_sb.jpg", + "url": "https://api.bestbuy.com/click/-/5580377/pdp", + "free_shipping": true, + "rating": 4, + "popularity": 19201, + "objectID": "5580377", + "_snippetResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ 6s 32GB - Space Gray (AT&T)", + "matchLevel": "full" + }, + "description": { + "value": "A 4.7-inch Retina HD display with 3D Touch. 7000 series aluminum and stronger cover glass. An A9 chip with 64-bit desktop-class architecture. All new 12MP iSight camera with Live Photos. Touch …", + "matchLevel": "none" + } + }, + "_highlightResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ 6s 32GB - Space Gray (AT&T)", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "description": { + "value": "A 4.7-inch Retina HD display with 3D Touch. 7000 series aluminum and stronger cover glass. An A9 chip with 64-bit desktop-class architecture. All new 12MP iSight camera with Live Photos. Touch ID. Faster LTE and Wi-Fi. Long battery life and iOS 10 and iCloud. All in a smooth, continuous unibody design.", + "matchLevel": "none", + "matchedWords": [] + }, + "brand": { + "value": "Apple", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Cell Phones", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__", + "matchLevel": "full", + "fullyHighlighted": true, + "matchedWords": ["iphone"] + } + ], + "type": { + "value": "Att iph unv handset", + "matchLevel": "none", + "matchedWords": [] + } + } + }, + { + "name": "Apple - iPhone SE 16GB - Rose Gold (Verizon)", + "description": "iPhone SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "brand": "Apple", + "categories": ["Cell Phones", "iPhone", "iPhone SE"], + "hierarchicalCategories": { + "lvl0": "Cell Phones", + "lvl1": "Cell Phones > iPhone", + "lvl2": "Cell Phones > iPhone > iPhone SE" + }, + "type": "Vzw iphone handset", + "price": 449.99, + "price_range": "200 - 500", + "image": "https://cdn-demo.algolia.com/bestbuy-0118/5005509_sb.jpg", + "url": "https://api.bestbuy.com/click/-/5005509/pdp", + "free_shipping": true, + "rating": 4, + "popularity": 19033, + "objectID": "5005509", + "_snippetResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Rose Gold (Verizon)", + "matchLevel": "full" + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos …", + "matchLevel": "full" + } + }, + "_highlightResult": { + "name": { + "value": "Apple - __aa-highlight__iPhone__/aa-highlight__ SE 16GB - Rose Gold (Verizon)", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "description": { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE features a 4-inch Retina display, an A9 chip with 64-bit desktop-class architecture, the Touch ID fingerprint sensor, a 12MP iSight camera, a FaceTime HD camera with Retina Flash, Live Photos, LTE and fast Wi-Fi, iOS 9, and iCloud.", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + }, + "brand": { + "value": "Apple", + "matchLevel": "none", + "matchedWords": [] + }, + "categories": [ + { + "value": "Cell Phones", + "matchLevel": "none", + "matchedWords": [] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__", + "matchLevel": "full", + "fullyHighlighted": true, + "matchedWords": ["iphone"] + }, + { + "value": "__aa-highlight__iPhone__/aa-highlight__ SE", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + ], + "type": { + "value": "Vzw __aa-highlight__iphone__/aa-highlight__ handset", + "matchLevel": "full", + "fullyHighlighted": false, + "matchedWords": ["iphone"] + } + } + } + ], + "userData": [ + { + "title": "iPhone Xs", + "banner": "https://user-images.githubusercontent.com/6137112/80473185-10281600-8946-11ea-9dbf-652dfbb7968b.png", + "link": "https://www.apple.com/iphone/" + } + ], + "nbHits": 3977, + "page": 0, + "nbPages": 200, + "hitsPerPage": 5, + "exhaustiveNbHits": true, + "query": "iphone", + "queryAfterRemoval": "iphone", + "params": "query=iphone&hitsPerPage=5&highlightPreTag=__aa-highlight__&highlightPostTag=__%2Faa-highlight__&clickAnalytics=true&attributesToSnippet=%5B%22name%3A10%22%2C%22description%3A35%22%5D&snippetEllipsisText=%E2%80%A6", + "index": "instant_search", + "queryID": "94e8a45fd0dc47b54627fb00342381b6", + "processingTimeMS": 2 + } + ] +} diff --git a/packages/autocomplete-js/src/__tests__/highlightHit.test.ts b/packages/autocomplete-js/src/__tests__/highlightHit.test.ts deleted file mode 100644 index 71c5d4b23..000000000 --- a/packages/autocomplete-js/src/__tests__/highlightHit.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { highlightHit } from '../highlight'; - -describe('highlightHit', () => { - test('returns a highlighted hit', () => { - expect( - highlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - }) - ).toEqual([ - 'amazon ', - expect.objectContaining({ - type: 'mark', - props: { - children: 'fire', - }, - }), - ' ', - expect.objectContaining({ - type: 'mark', - props: { - children: 'tablet', - }, - }), - 's', - ]); - }); - - test('accepts custom createElement', () => { - expect( - highlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - createElement(type, props, children) { - return { - type, - props, - children, - }; - }, - }) - ).toEqual([ - 'amazon ', - expect.objectContaining({ - type: 'mark', - props: { - key: 1, - }, - children: 'fire', - }), - ' ', - expect.objectContaining({ - type: 'mark', - props: { - key: 3, - }, - children: 'tablet', - }), - 's', - ]); - }); -}); diff --git a/packages/autocomplete-js/src/__tests__/reverseHighlightHit.test.ts b/packages/autocomplete-js/src/__tests__/reverseHighlightHit.test.ts deleted file mode 100644 index d2e131c61..000000000 --- a/packages/autocomplete-js/src/__tests__/reverseHighlightHit.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { reverseHighlightHit } from '../highlight'; - -describe('reverseHighlightHit', () => { - test('returns a reversed partially highlighted hit', () => { - expect( - reverseHighlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - }) - ).toEqual([ - expect.objectContaining({ - type: 'mark', - props: { - children: 'amazon ', - }, - }), - 'fire', - ' ', - 'tablet', - expect.objectContaining({ - type: 'mark', - props: { - children: 's', - }, - }), - ]); - }); - - test('returns a reversed fully highlighted hit', () => { - expect( - reverseHighlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: ['amazon', 'fire', 'tablet'], - value: - '__aa-highlight__amazon__/aa-highlight__ __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablets__/aa-highlight__', - }, - }, - }, - attribute: 'query', - }) - ).toEqual(['amazon', ' ', 'fire', ' ', 'tablets']); - }); - - test('returns a reversed empty highlighted query hit', () => { - expect( - reverseHighlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: false, - matchLevel: 'none', - matchedWords: [], - value: 'amazon fire tablets', - }, - }, - }, - attribute: 'query', - }) - ).toEqual(['amazon fire tablets']); - }); - - test('accepts custom createElement', () => { - expect( - reverseHighlightHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _highlightResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - createElement(type, props, children) { - return { - type, - props, - children, - }; - }, - }) - ).toEqual([ - expect.objectContaining({ - type: 'mark', - props: { - key: 0, - }, - children: 'amazon ', - }), - 'fire', - ' ', - 'tablet', - expect.objectContaining({ - type: 'mark', - props: { - key: 4, - }, - children: 's', - }), - ]); - }); -}); diff --git a/packages/autocomplete-js/src/__tests__/reverseSnippetHit.test.ts b/packages/autocomplete-js/src/__tests__/reverseSnippetHit.test.ts deleted file mode 100644 index 9ae8b782b..000000000 --- a/packages/autocomplete-js/src/__tests__/reverseSnippetHit.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { reverseSnippetHit } from '../highlight'; - -describe('reverseSnippetHit', () => { - test('returns a reversed partially snippeted hit', () => { - expect( - reverseSnippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - }) - ).toEqual([ - expect.objectContaining({ - type: 'mark', - props: { - children: 'amazon ', - }, - }), - 'fire', - ' ', - 'tablet', - expect.objectContaining({ - type: 'mark', - props: { - children: 's', - }, - }), - ]); - }); - - test('returns a reversed fully snippeted hit', () => { - expect( - reverseSnippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: true, - matchLevel: 'full', - matchedWords: ['amazon', 'fire', 'tablet'], - value: - '__aa-highlight__amazon__/aa-highlight__ __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablets__/aa-highlight__', - }, - }, - }, - attribute: 'query', - }) - ).toEqual(['amazon', ' ', 'fire', ' ', 'tablets']); - }); - - test('returns a reversed empty snippeted query hit', () => { - expect( - reverseSnippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: false, - matchLevel: 'none', - matchedWords: [], - value: 'amazon fire tablets', - }, - }, - }, - attribute: 'query', - }) - ).toEqual(['amazon fire tablets']); - }); - - test('accepts custom createElement', () => { - expect( - reverseSnippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - createElement(type, props, children) { - return { - type, - props, - children, - }; - }, - }) - ).toEqual([ - expect.objectContaining({ - type: 'mark', - props: { - key: 0, - }, - children: 'amazon ', - }), - 'fire', - ' ', - 'tablet', - expect.objectContaining({ - type: 'mark', - props: { - key: 4, - }, - children: 's', - }), - ]); - }); -}); diff --git a/packages/autocomplete-js/src/__tests__/snippetHit.test.ts b/packages/autocomplete-js/src/__tests__/snippetHit.test.ts deleted file mode 100644 index 1f7483a06..000000000 --- a/packages/autocomplete-js/src/__tests__/snippetHit.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { snippetHit } from '../highlight'; - -describe('snippetHit', () => { - test('returns a snippeted hit', () => { - expect( - snippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - }) - ).toEqual([ - 'amazon ', - expect.objectContaining({ - type: 'mark', - props: { - children: 'fire', - }, - }), - ' ', - expect.objectContaining({ - type: 'mark', - props: { - children: 'tablet', - }, - }), - 's', - ]); - }); - - test('accepts custom createElement', () => { - expect( - snippetHit({ - hit: { - objectID: 'amazon fire tablets', - query: 'amazon fire tablets', - _snippetResult: { - query: { - fullyHighlighted: false, - matchLevel: 'full', - matchedWords: ['fire', 'tablet'], - value: - 'amazon __aa-highlight__fire__/aa-highlight__ __aa-highlight__tablet__/aa-highlight__s', - }, - }, - }, - attribute: 'query', - createElement(type, props, children) { - return { - type, - props, - children, - }; - }, - }) - ).toEqual([ - 'amazon ', - expect.objectContaining({ - type: 'mark', - props: { - key: 1, - }, - children: 'fire', - }), - ' ', - expect.objectContaining({ - type: 'mark', - props: { - key: 3, - }, - children: 'tablet', - }), - 's', - ]); - }); -}); diff --git a/packages/autocomplete-js/src/autocomplete.ts b/packages/autocomplete-js/src/autocomplete.ts index 112e37028..352b4c119 100644 --- a/packages/autocomplete-js/src/autocomplete.ts +++ b/packages/autocomplete-js/src/autocomplete.ts @@ -135,6 +135,7 @@ export function autocomplete( autocomplete: autocomplete.value, autocompleteScopeApi, classNames: props.value.renderer.classNames, + components: props.value.renderer.components, container: props.value.renderer.container, createElement: props.value.renderer.renderer.createElement, dom: dom.value, diff --git a/packages/autocomplete-js/src/components/Highlight.ts b/packages/autocomplete-js/src/components/Highlight.ts new file mode 100644 index 000000000..3faa0cca5 --- /dev/null +++ b/packages/autocomplete-js/src/components/Highlight.ts @@ -0,0 +1,24 @@ +import { parseAlgoliaHitHighlight } from '@algolia/autocomplete-preset-algolia'; + +import { AutocompleteRenderer, HighlightHitParams } from '../types'; + +export function createHighlightComponent({ + createElement, + Fragment, +}: AutocompleteRenderer) { + return function Highlight({ + hit, + attribute, + tagName = 'mark', + }: HighlightHitParams): JSX.Element { + return createElement( + Fragment, + {}, + ...parseAlgoliaHitHighlight({ hit, attribute }).map((x, index) => + x.isHighlighted + ? createElement(tagName, { key: index }, x.value) + : x.value + ) + ); + }; +} diff --git a/packages/autocomplete-js/src/components/ReverseHighlight.ts b/packages/autocomplete-js/src/components/ReverseHighlight.ts new file mode 100644 index 000000000..f19ac4210 --- /dev/null +++ b/packages/autocomplete-js/src/components/ReverseHighlight.ts @@ -0,0 +1,27 @@ +import { parseAlgoliaHitReverseHighlight } from '@algolia/autocomplete-preset-algolia'; + +import { AutocompleteRenderer, HighlightHitParams } from '../types'; + +export function createReverseHighlightComponent({ + createElement, + Fragment, +}: AutocompleteRenderer) { + return function ReverseHighlight({ + hit, + attribute, + tagName = 'mark', + }: HighlightHitParams): JSX.Element { + return createElement( + Fragment, + {}, + ...parseAlgoliaHitReverseHighlight({ + hit, + attribute, + }).map((x, index) => + x.isHighlighted + ? createElement(tagName, { key: index }, x.value) + : x.value + ) + ); + }; +} diff --git a/packages/autocomplete-js/src/components/ReverseSnippet.ts b/packages/autocomplete-js/src/components/ReverseSnippet.ts new file mode 100644 index 000000000..11e0f5d69 --- /dev/null +++ b/packages/autocomplete-js/src/components/ReverseSnippet.ts @@ -0,0 +1,27 @@ +import { parseAlgoliaHitReverseSnippet } from '@algolia/autocomplete-preset-algolia'; + +import { AutocompleteRenderer, HighlightHitParams } from '../types'; + +export function createReverseSnippetComponent({ + createElement, + Fragment, +}: AutocompleteRenderer) { + return function ReverseSnippet({ + hit, + attribute, + tagName = 'mark', + }: HighlightHitParams): JSX.Element { + return createElement( + Fragment, + {}, + ...parseAlgoliaHitReverseSnippet({ + hit, + attribute, + }).map((x, index) => + x.isHighlighted + ? createElement(tagName, { key: index }, x.value) + : x.value + ) + ); + }; +} diff --git a/packages/autocomplete-js/src/components/Snippet.ts b/packages/autocomplete-js/src/components/Snippet.ts new file mode 100644 index 000000000..910b7be5a --- /dev/null +++ b/packages/autocomplete-js/src/components/Snippet.ts @@ -0,0 +1,24 @@ +import { parseAlgoliaHitSnippet } from '@algolia/autocomplete-preset-algolia'; + +import { AutocompleteRenderer, HighlightHitParams } from '../types'; + +export function createSnippetComponent({ + createElement, + Fragment, +}: AutocompleteRenderer) { + return function Snippet({ + hit, + attribute, + tagName = 'mark', + }: HighlightHitParams): JSX.Element { + return createElement( + Fragment, + {}, + ...parseAlgoliaHitSnippet({ hit, attribute }).map((x, index) => + x.isHighlighted + ? createElement(tagName, { key: index }, x.value) + : x.value + ) + ); + }; +} diff --git a/packages/autocomplete-js/src/components/index.ts b/packages/autocomplete-js/src/components/index.ts index 7bc3d23a0..2f1cf3167 100644 --- a/packages/autocomplete-js/src/components/index.ts +++ b/packages/autocomplete-js/src/components/index.ts @@ -1,4 +1,4 @@ -export * from './ClearIcon'; -export * from './Input'; -export * from './LoadingIcon'; -export * from './SearchIcon'; +export * from './Highlight'; +export * from './ReverseHighlight'; +export * from './ReverseSnippet'; +export * from './Snippet'; diff --git a/packages/autocomplete-js/src/createAutocompleteDom.ts b/packages/autocomplete-js/src/createAutocompleteDom.ts index 3ab35f8e8..b8b2dd906 100644 --- a/packages/autocomplete-js/src/createAutocompleteDom.ts +++ b/packages/autocomplete-js/src/createAutocompleteDom.ts @@ -4,8 +4,8 @@ import { BaseItem, } from '@algolia/autocomplete-core'; -import { ClearIcon, Input, LoadingIcon, SearchIcon } from './components'; import { createDomElement } from './createDomElement'; +import { ClearIcon, Input, LoadingIcon, SearchIcon } from './elements'; import { AutocompleteClassNames, AutocompleteDom, diff --git a/packages/autocomplete-js/src/components/ClearIcon.ts b/packages/autocomplete-js/src/elements/ClearIcon.ts similarity index 85% rename from packages/autocomplete-js/src/components/ClearIcon.ts rename to packages/autocomplete-js/src/elements/ClearIcon.ts index 3102374bf..ee7ba4f5b 100644 --- a/packages/autocomplete-js/src/components/ClearIcon.ts +++ b/packages/autocomplete-js/src/elements/ClearIcon.ts @@ -1,6 +1,6 @@ -import { Component } from '../types/Component'; +import { AutocompleteElement } from '../types/AutocompleteElement'; -export const ClearIcon: Component<{}, SVGSVGElement> = () => { +export const ClearIcon: AutocompleteElement<{}, SVGSVGElement> = () => { const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); element.setAttribute('class', 'aa-ClearIcon'); element.setAttribute('viewBox', '0 0 24 24'); diff --git a/packages/autocomplete-js/src/components/Input.ts b/packages/autocomplete-js/src/elements/Input.ts similarity index 88% rename from packages/autocomplete-js/src/components/Input.ts rename to packages/autocomplete-js/src/elements/Input.ts index 7d9086f13..be9d6cca9 100644 --- a/packages/autocomplete-js/src/components/Input.ts +++ b/packages/autocomplete-js/src/elements/Input.ts @@ -5,7 +5,7 @@ import { import { createDomElement } from '../createDomElement'; import { AutocompletePropGetters, AutocompleteState } from '../types'; -import { Component } from '../types/Component'; +import { AutocompleteElement } from '../types/AutocompleteElement'; import { setProperties } from '../utils'; type InputProps = { @@ -16,7 +16,7 @@ type InputProps = { state: AutocompleteState; }; -export const Input: Component = ({ +export const Input: AutocompleteElement = ({ autocompleteScopeApi, classNames, getInputProps, diff --git a/packages/autocomplete-js/src/components/LoadingIcon.ts b/packages/autocomplete-js/src/elements/LoadingIcon.ts similarity index 82% rename from packages/autocomplete-js/src/components/LoadingIcon.ts rename to packages/autocomplete-js/src/elements/LoadingIcon.ts index 40d86cde4..46e4d2b86 100644 --- a/packages/autocomplete-js/src/components/LoadingIcon.ts +++ b/packages/autocomplete-js/src/elements/LoadingIcon.ts @@ -1,6 +1,6 @@ -import { Component } from '../types/Component'; +import { AutocompleteElement } from '../types/AutocompleteElement'; -export const LoadingIcon: Component<{}, SVGSVGElement> = () => { +export const LoadingIcon: AutocompleteElement<{}, SVGSVGElement> = () => { const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); element.setAttribute('class', 'aa-LoadingIcon'); element.setAttribute('viewBox', '0 0 100 100'); diff --git a/packages/autocomplete-js/src/components/SearchIcon.ts b/packages/autocomplete-js/src/elements/SearchIcon.ts similarity index 88% rename from packages/autocomplete-js/src/components/SearchIcon.ts rename to packages/autocomplete-js/src/elements/SearchIcon.ts index 708097cd1..9c5a3d19f 100644 --- a/packages/autocomplete-js/src/components/SearchIcon.ts +++ b/packages/autocomplete-js/src/elements/SearchIcon.ts @@ -1,6 +1,6 @@ -import { Component } from '../types/Component'; +import { AutocompleteElement } from '../types/AutocompleteElement'; -export const SearchIcon: Component<{}, SVGSVGElement> = () => { +export const SearchIcon: AutocompleteElement<{}, SVGSVGElement> = () => { const element = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); element.setAttribute('class', 'aa-SubmitIcon'); element.setAttribute('viewBox', '0 0 24 24'); diff --git a/packages/autocomplete-js/src/elements/index.ts b/packages/autocomplete-js/src/elements/index.ts new file mode 100644 index 000000000..7bc3d23a0 --- /dev/null +++ b/packages/autocomplete-js/src/elements/index.ts @@ -0,0 +1,4 @@ +export * from './ClearIcon'; +export * from './Input'; +export * from './LoadingIcon'; +export * from './SearchIcon'; diff --git a/packages/autocomplete-js/src/getDefaultOptions.ts b/packages/autocomplete-js/src/getDefaultOptions.ts index 5fe19d88d..0a0b81cd0 100644 --- a/packages/autocomplete-js/src/getDefaultOptions.ts +++ b/packages/autocomplete-js/src/getDefaultOptions.ts @@ -9,8 +9,15 @@ import { render, } from 'preact'; +import { + createHighlightComponent, + createReverseHighlightComponent, + createReverseSnippetComponent, + createSnippetComponent, +} from './components'; import { AutocompleteClassNames, + AutocompleteComponents, AutocompleteOptions, AutocompleteRender, AutocompleteRenderer, @@ -74,6 +81,7 @@ export function getDefaultOptions( renderNoResults, renderer, detachedMediaQuery, + components, ...core } = options; @@ -87,6 +95,13 @@ export function getDefaultOptions( const environment = (typeof window !== 'undefined' ? window : {}) as typeof window; + const defaultedRenderer = renderer ?? defaultRenderer; + const defaultComponents: AutocompleteComponents = { + Highlight: createHighlightComponent(defaultedRenderer), + ReverseHighlight: createReverseHighlightComponent(defaultedRenderer), + ReverseSnippet: createReverseSnippetComponent(defaultedRenderer), + Snippet: createSnippetComponent(defaultedRenderer), + }; return { renderer: { @@ -109,12 +124,16 @@ export function getDefaultOptions( panelPlacement: panelPlacement ?? 'input-wrapper-width', render: render ?? defaultRender, renderNoResults, - renderer: renderer ?? defaultRenderer, + renderer: defaultedRenderer, detachedMediaQuery: detachedMediaQuery ?? getComputedStyle(environment.document.documentElement).getPropertyValue( '--aa-detached-media-query' ), + components: { + ...defaultComponents, + ...components, + }, }, core: { ...core, diff --git a/packages/autocomplete-js/src/highlight.ts b/packages/autocomplete-js/src/highlight.ts deleted file mode 100644 index 9c33e6c63..000000000 --- a/packages/autocomplete-js/src/highlight.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { - parseAlgoliaHitHighlight, - parseAlgoliaHitReverseHighlight, - parseAlgoliaHitReverseSnippet, - parseAlgoliaHitSnippet, - HighlightedHit, - SnippetedHit, -} from '@algolia/autocomplete-preset-algolia'; -import { createElement as preactCreateElement } from 'preact'; - -import { AutocompleteRenderer } from './types'; - -type HighlightItemParams = { - hit: THit; - attribute: keyof THit | string[]; - tagName?: string; - createElement?: AutocompleteRenderer['createElement']; -}; - -/** - * Highlights and escapes the matching parts of an Algolia hit. - */ -export function highlightHit>({ - hit, - attribute, - tagName = 'mark', - createElement = preactCreateElement, -}: HighlightItemParams) { - return parseAlgoliaHitHighlight({ hit, attribute }).map((x, index) => - x.isHighlighted ? createElement(tagName, { key: index }, x.value) : x.value - ); -} - -/** - * Highlights and escapes the non-matching parts of an Algolia hit. - * - * This is a common pattern for Query Suggestions. - */ -export function reverseHighlightHit>({ - hit, - attribute, - tagName = 'mark', - createElement = preactCreateElement, -}: HighlightItemParams) { - return parseAlgoliaHitReverseHighlight({ - hit, - attribute, - }).map((x, index) => - x.isHighlighted ? createElement(tagName, { key: index }, x.value) : x.value - ); -} - -/** - * Highlights and escapes the matching parts of an Algolia hit snippet. - */ -export function snippetHit>({ - hit, - attribute, - tagName = 'mark', - createElement = preactCreateElement, -}: HighlightItemParams) { - return parseAlgoliaHitSnippet({ hit, attribute }).map((x, index) => - x.isHighlighted ? createElement(tagName, { key: index }, x.value) : x.value - ); -} - -/** - * Highlights and escapes the non-matching parts of an Algolia hit snippet. - * - * This is a common pattern for Query Suggestions. - */ -export function reverseSnippetHit>({ - hit, - attribute, - tagName = 'mark', - createElement = preactCreateElement, -}: HighlightItemParams) { - return parseAlgoliaHitReverseSnippet({ - hit, - attribute, - }).map((x, index) => - x.isHighlighted ? createElement(tagName, { key: index }, x.value) : x.value - ); -} diff --git a/packages/autocomplete-js/src/index.ts b/packages/autocomplete-js/src/index.ts index 3d3f37812..32dfb3a61 100644 --- a/packages/autocomplete-js/src/index.ts +++ b/packages/autocomplete-js/src/index.ts @@ -2,5 +2,4 @@ export * from './autocomplete'; export * from './getAlgoliaFacetHits'; export * from './getAlgoliaHits'; export * from './getAlgoliaResults'; -export * from './highlight'; export * from './types'; diff --git a/packages/autocomplete-js/src/render.tsx b/packages/autocomplete-js/src/render.tsx index 385b5cdc0..283f5d8da 100644 --- a/packages/autocomplete-js/src/render.tsx +++ b/packages/autocomplete-js/src/render.tsx @@ -7,6 +7,7 @@ import { BaseItem } from '@algolia/autocomplete-core/src'; import { AutocompleteClassNames, + AutocompleteComponents, AutocompleteDom, AutocompletePropGetters, AutocompleteRender, @@ -20,6 +21,7 @@ type RenderProps = { autocomplete: AutocompleteCoreApi; autocompleteScopeApi: AutocompleteScopeApi; classNames: AutocompleteClassNames; + components: AutocompleteComponents; createElement: Pragma; dom: AutocompleteDom; Fragment: PragmaFrag; @@ -69,6 +71,7 @@ export function renderPanel( panelContainer, propGetters, state, + components, }: RenderProps ): void { if (!state.isOpen) { @@ -96,6 +99,7 @@ export function renderPanel( {source.templates.header && (
{source.templates.header({ + components, createElement, Fragment, items, @@ -108,6 +112,7 @@ export function renderPanel( {items.length === 0 && source.templates.noResults && state.query ? (
{source.templates.noResults({ + components, createElement, Fragment, source, @@ -140,6 +145,7 @@ export function renderPanel( })} > {source.templates.item({ + components, createElement, Fragment, item, @@ -154,6 +160,7 @@ export function renderPanel( {source.templates.footer && (
{source.templates.footer({ + components, createElement, Fragment, items, @@ -174,7 +181,15 @@ export function renderPanel( }, {}); render( - { children, state, sections, elements, createElement, Fragment }, + { + children, + state, + sections, + elements, + createElement, + Fragment, + components, + }, dom.panel ); } diff --git a/packages/autocomplete-js/src/types/AutocompleteComponents.ts b/packages/autocomplete-js/src/types/AutocompleteComponents.ts new file mode 100644 index 000000000..bc7bd0213 --- /dev/null +++ b/packages/autocomplete-js/src/types/AutocompleteComponents.ts @@ -0,0 +1,19 @@ +import { HighlightHitParams } from '.'; + +type AutocompleteHighlightComponent = ({ + hit, + attribute, + tagName, +}: HighlightHitParams) => JSX.Element; + +export type PublicAutocompleteComponents = Record< + string, + (props: any) => JSX.Element +>; + +export interface AutocompleteComponents extends PublicAutocompleteComponents { + Highlight: AutocompleteHighlightComponent; + ReverseHighlight: AutocompleteHighlightComponent; + ReverseSnippet: AutocompleteHighlightComponent; + Snippet: AutocompleteHighlightComponent; +} diff --git a/packages/autocomplete-js/src/types/Component.ts b/packages/autocomplete-js/src/types/AutocompleteElement.ts similarity index 50% rename from packages/autocomplete-js/src/types/Component.ts rename to packages/autocomplete-js/src/types/AutocompleteElement.ts index b2bfa794a..ac9fdcc5e 100644 --- a/packages/autocomplete-js/src/types/Component.ts +++ b/packages/autocomplete-js/src/types/AutocompleteElement.ts @@ -1,9 +1,9 @@ -type WithComponentProps = TProps & +type WithElementProps = TProps & Record & { children?: Node[]; }; -export type Component< +export type AutocompleteElement< TProps = {}, TElement extends HTMLOrSVGElement = HTMLOrSVGElement -> = (props: WithComponentProps) => TElement; +> = (props: WithElementProps) => TElement; diff --git a/packages/autocomplete-js/src/types/AutocompleteOptions.ts b/packages/autocomplete-js/src/types/AutocompleteOptions.ts index 51411c9a4..f99aa3302 100644 --- a/packages/autocomplete-js/src/types/AutocompleteOptions.ts +++ b/packages/autocomplete-js/src/types/AutocompleteOptions.ts @@ -7,6 +7,7 @@ import { import { MaybePromise } from '@algolia/autocomplete-shared'; import { AutocompleteClassNames } from './AutocompleteClassNames'; +import { PublicAutocompleteComponents } from './AutocompleteComponents'; import { AutocompletePlugin } from './AutocompletePlugin'; import { AutocompletePropGetters } from './AutocompletePropGetters'; import { AutocompleteRender } from './AutocompleteRender'; @@ -73,4 +74,5 @@ export interface AutocompleteOptions */ renderer?: AutocompleteRenderer; plugins?: Array>; + components?: PublicAutocompleteComponents; } diff --git a/packages/autocomplete-js/src/types/AutocompleteRender.ts b/packages/autocomplete-js/src/types/AutocompleteRender.ts index fceaee488..e528a066e 100644 --- a/packages/autocomplete-js/src/types/AutocompleteRender.ts +++ b/packages/autocomplete-js/src/types/AutocompleteRender.ts @@ -1,5 +1,6 @@ import { BaseItem } from '@algolia/autocomplete-core'; +import { AutocompleteComponents } from './AutocompleteComponents'; import { Pragma, PragmaFrag, VNode } from './AutocompleteRenderer'; import { AutocompleteState } from './AutocompleteState'; @@ -9,6 +10,7 @@ export type AutocompleteRender = ( state: AutocompleteState; sections: VNode[]; elements: Record; + components: AutocompleteComponents; createElement: Pragma; Fragment: PragmaFrag; }, diff --git a/packages/autocomplete-js/src/types/AutocompleteRenderer.ts b/packages/autocomplete-js/src/types/AutocompleteRenderer.ts index b495f2ba1..e2d310b03 100644 --- a/packages/autocomplete-js/src/types/AutocompleteRenderer.ts +++ b/packages/autocomplete-js/src/types/AutocompleteRenderer.ts @@ -2,7 +2,7 @@ export type Pragma = ( type: any, props: Record | null, ...children: ComponentChildren[] -) => VNode; +) => JSX.Element; export type PragmaFrag = any; type ComponentChild = @@ -17,7 +17,7 @@ type ComponentChildren = ComponentChild[] | ComponentChild; export type VNode = { type: any; - props: TProps & { children: ComponentChildren }; + props: TProps & { children: ComponentChildren; key?: any }; }; export type AutocompleteRenderer = { diff --git a/packages/autocomplete-js/src/types/AutocompleteSource.ts b/packages/autocomplete-js/src/types/AutocompleteSource.ts index 8a6bbc0cd..b11f95274 100644 --- a/packages/autocomplete-js/src/types/AutocompleteSource.ts +++ b/packages/autocomplete-js/src/types/AutocompleteSource.ts @@ -4,11 +4,16 @@ import { BaseItem, } from '@algolia/autocomplete-core'; +import { AutocompleteComponents } from './AutocompleteComponents'; import { Pragma, PragmaFrag, VNode } from './AutocompleteRenderer'; import { AutocompleteState } from './AutocompleteState'; type Template = ( - params: TParams & { createElement: Pragma; Fragment: PragmaFrag } + params: TParams & { + createElement: Pragma; + Fragment: PragmaFrag; + components: AutocompleteComponents; + } ) => VNode | string; /** diff --git a/packages/autocomplete-js/src/types/HighlightHitParams.ts b/packages/autocomplete-js/src/types/HighlightHitParams.ts new file mode 100644 index 000000000..3cbef7cf0 --- /dev/null +++ b/packages/autocomplete-js/src/types/HighlightHitParams.ts @@ -0,0 +1,5 @@ +export type HighlightHitParams = { + hit: THit; + attribute: keyof THit | string[]; + tagName?: string; +}; diff --git a/packages/autocomplete-js/src/types/index.ts b/packages/autocomplete-js/src/types/index.ts index 73fc8d0b4..708ad8837 100644 --- a/packages/autocomplete-js/src/types/index.ts +++ b/packages/autocomplete-js/src/types/index.ts @@ -1,6 +1,7 @@ export * from './AutocompleteApi'; export * from './AutocompleteClassNames'; export * from './AutocompleteCollection'; +export * from './AutocompleteComponents'; export * from './AutocompleteDom'; export * from './AutocompleteOptions'; export * from './AutocompletePlugin'; @@ -9,3 +10,4 @@ export * from './AutocompleteRender'; export * from './AutocompleteRenderer'; export * from './AutocompleteSource'; export * from './AutocompleteState'; +export * from './HighlightHitParams'; diff --git a/packages/autocomplete-plugin-query-suggestions/src/getTemplates.tsx b/packages/autocomplete-plugin-query-suggestions/src/getTemplates.tsx index 4715c29d4..23fd3e110 100644 --- a/packages/autocomplete-plugin-query-suggestions/src/getTemplates.tsx +++ b/packages/autocomplete-plugin-query-suggestions/src/getTemplates.tsx @@ -1,5 +1,5 @@ /** @jsx createElement */ -import { reverseHighlightHit, SourceTemplates } from '@algolia/autocomplete-js'; +import { SourceTemplates } from '@algolia/autocomplete-js'; import { QuerySuggestionsHit } from './types'; @@ -11,7 +11,7 @@ export function getTemplates({ onTapAhead, }: GetTemplatesParams): SourceTemplates { return { - item({ item, createElement, Fragment }) { + item({ item, createElement, Fragment, components }) { return (
@@ -37,11 +37,7 @@ export function getTemplates({
) : ( - reverseHighlightHit({ - hit: item, - attribute: 'query', - createElement, - }) + )}
diff --git a/packages/autocomplete-plugin-recent-searches/src/getTemplates.tsx b/packages/autocomplete-plugin-recent-searches/src/getTemplates.tsx index 1cffd4b45..d89237a8f 100644 --- a/packages/autocomplete-plugin-recent-searches/src/getTemplates.tsx +++ b/packages/autocomplete-plugin-recent-searches/src/getTemplates.tsx @@ -1,6 +1,5 @@ /** @jsx createElement */ -import { reverseHighlightHit, SourceTemplates } from '@algolia/autocomplete-js'; -import { HighlightedHit } from '@algolia/autocomplete-preset-algolia'; +import { SourceTemplates } from '@algolia/autocomplete-js'; import { RecentSearchesItem } from './types'; @@ -14,7 +13,7 @@ export function getTemplates({ onTapAhead, }: GetTemplatesParams): SourceTemplates { return { - item({ item, createElement, Fragment }) { + item({ item, createElement, Fragment, components }) { return (
@@ -24,11 +23,7 @@ export function getTemplates({
- {reverseHighlightHit>({ - hit: item, - attribute: 'label', - createElement, - })} +
{item.category && ( diff --git a/packages/website/docs/autocomplete-js.md b/packages/website/docs/autocomplete-js.md index fea28e2b6..b1122a3b2 100644 --- a/packages/website/docs/autocomplete-js.md +++ b/packages/website/docs/autocomplete-js.md @@ -39,13 +39,9 @@ Make sure to define an empty container in your HTML where to inject your autocom This example uses Autocomplete with an Algolia index, along with the [`algoliasearch`](https://www.npmjs.com/package/algoliasearch) API client. All Algolia utility functions to retrieve hits and parse results are available directly in the package. -```js title="JavaScript" +```jsx title="JavaScript" import algoliasearch from 'algoliasearch/lite'; -import { - autocomplete, - getAlgoliaHits, - reverseHighlightHit, -} from '@algolia/autocomplete-js'; +import { autocomplete, getAlgoliaHits } from '@algolia/autocomplete-js'; const searchClient = algoliasearch( 'latency', @@ -74,8 +70,8 @@ const autocompleteSearch = autocomplete({ }); }, templates: { - item({ item }) { - return reverseHighlightHit({ hit: item, attribute: 'query' }); + item({ item, components }) { + return ; }, }, }, diff --git a/packages/website/docs/autocomplete-theme-classic.md b/packages/website/docs/autocomplete-theme-classic.md index b06ef18ca..ae8033298 100644 --- a/packages/website/docs/autocomplete-theme-classic.md +++ b/packages/website/docs/autocomplete-theme-classic.md @@ -49,7 +49,7 @@ To customize a value, you can create a custom stylesheet and override the variab } ``` -Make sure to load these styles *after* the theme. +Make sure to load these styles _after_ the theme. ## Templates @@ -63,7 +63,7 @@ Here's the markup for an [`item`](templates#item) template. autocomplete({ // ... templates: { - item({ item }) { + item({ item, components }) { return (
@@ -71,10 +71,10 @@ autocomplete({
- {snippetHit({ hit: item, attribute: 'name' })} +
- {snippetHit({ hit: item, attribute: 'description' })} +
diff --git a/packages/website/docs/getAlgoliaFacetHits.md b/packages/website/docs/getAlgoliaFacetHits.mdx similarity index 94% rename from packages/website/docs/getAlgoliaFacetHits.md rename to packages/website/docs/getAlgoliaFacetHits.mdx index 55f6c0266..362ae8ce5 100644 --- a/packages/website/docs/getAlgoliaFacetHits.md +++ b/packages/website/docs/getAlgoliaFacetHits.mdx @@ -2,8 +2,8 @@ id: getAlgoliaFacetHits --- -import GetAlgoliaFacetHitsIntro from './partials/preset-algolia/getAlgoliaFacetHits/intro.md' -import PresetAlgoliaNote from './partials/preset-algolia/note.md' +import GetAlgoliaFacetHitsIntro from './partials/preset-algolia/getAlgoliaFacetHits/intro.md'; +import PresetAlgoliaNote from './partials/preset-algolia/note.md'; @@ -89,7 +89,7 @@ These are the default parameters. You can leave them as is and specify other par :::info -If you override `highlightPreTag` and `highlightPostTag`, you won't be able to use the built-in highlighting utilities such as [`highlightHit`](highlightHit). +If you override `highlightPreTag` and `highlightPostTag`, you won't be able to use the built-in highlighting components such as `Highlight`. ::: diff --git a/packages/website/docs/getting-started.mdx b/packages/website/docs/getting-started.mdx index aeed816cc..debe75852 100644 --- a/packages/website/docs/getting-started.mdx +++ b/packages/website/docs/getting-started.mdx @@ -155,11 +155,7 @@ The given `classNames` correspond to the [classic theme](autocomplete-theme-clas ```jsx title="app.jsx" /** @jsx h */ -import { - autocomplete, - getAlgoliaHits, - snippetHit, -} from '@algolia/autocomplete-js'; +import { autocomplete, getAlgoliaHits } from '@algolia/autocomplete-js'; import algoliasearch from 'algoliasearch'; import { h, Fragment } from 'preact'; @@ -194,8 +190,8 @@ autocomplete({ }); }, templates: { - item({ item }) { - return ; + item({ item, components }) { + return ; }, }, }, @@ -203,7 +199,7 @@ autocomplete({ }, }); -function ProductItem({ hit }: ProductItemProps) { +function ProductItem({ hit, components }: ProductItemProps) { return (
@@ -211,10 +207,10 @@ function ProductItem({ hit }: ProductItemProps) {
- {snippetHit({ hit, attribute: 'name' })} +
- {snippetHit({ hit, attribute: 'description' })} +
@@ -242,7 +238,7 @@ function ProductItem({ hit }: ProductItemProps) { } ``` -The `ProductItem` component uses the [`snippetHit`](snippetHit) function to only display part of the item's name and description, if they go beyond a certain length. Each attribute's allowed length and the characters to show when truncated are defined in the [`attributesToSnippet`](https://www.algolia.com/doc/api-reference/api-parameters/attributesToSnippet/) and [`snippetEllipsisText`](https://www.algolia.com/doc/api-reference/api-parameters/snippetEllipsisText/) [Algolia query parameters](https://www.algolia.com/doc/api-reference/api-parameters/) in `params`. +The `ProductItem` component uses the `Snippet` component to only display part of the item's name and description, if they go beyond a certain length. Each attribute's allowed length and the characters to show when truncated are defined in the [`attributesToSnippet`](https://www.algolia.com/doc/api-reference/api-parameters/attributesToSnippet/) and [`snippetEllipsisText`](https://www.algolia.com/doc/api-reference/api-parameters/snippetEllipsisText/) [Algolia query parameters](https://www.algolia.com/doc/api-reference/api-parameters/) in `params`. This is what the truncated JSON record looks like: diff --git a/packages/website/docs/sending-algolia-insights-events.md b/packages/website/docs/sending-algolia-insights-events.md index 522a5afe2..06665474c 100644 --- a/packages/website/docs/sending-algolia-insights-events.md +++ b/packages/website/docs/sending-algolia-insights-events.md @@ -35,11 +35,7 @@ If you haven't implemented an autocomplete using Algolia as a source yet, follow First, begin with some boilerplate for the autocomplete implementation. Create a file called `index.js` in your `src` directory, and add the boilerplate below: ```js title="index.js" -import { - autocomplete, - getAlgoliaHits, - highlightHit, -} from '@algolia/autocomplete-js'; +import { autocomplete, getAlgoliaHits } from '@algolia/autocomplete-js'; import algoliasearch from 'algoliasearch'; import { h, Fragment } from 'preact'; @@ -70,8 +66,8 @@ autocomplete({ }); }, templates: { - item({ item }) { - return ; + item({ item, components }) { + return ; }, }, }, @@ -79,7 +75,7 @@ autocomplete({ }, }); -function ProductItem({ hit }) { +function ProductItem({ hit, components }) { return (
@@ -87,10 +83,10 @@ function ProductItem({ hit }) {
- {highlightHit({ hit, attribute: 'name' })} +
- {highlightHit({ hit, attribute: 'description' })} +