instantsearch.js 4.68.1 → 4.70.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/cjs/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.js +93 -0
  2. package/cjs/connectors/index.js +28 -0
  3. package/cjs/connectors/looking-similar/connectLookingSimilar.js +94 -0
  4. package/cjs/connectors/related-products/connectRelatedProducts.js +94 -0
  5. package/cjs/connectors/trending-items/connectTrendingItems.js +90 -0
  6. package/cjs/lib/InstantSearch.js +10 -1
  7. package/cjs/lib/server.js +28 -9
  8. package/cjs/lib/utils/addWidgetId.js +17 -0
  9. package/cjs/lib/utils/hydrateRecommendCache.js +23 -0
  10. package/cjs/lib/utils/hydrateSearchClient.js +7 -3
  11. package/cjs/lib/utils/index.js +22 -0
  12. package/cjs/lib/utils/render-args.js +3 -3
  13. package/cjs/lib/version.js +1 -1
  14. package/cjs/widgets/frequently-bought-together/frequently-bought-together.js +120 -0
  15. package/cjs/widgets/index/index.js +89 -20
  16. package/cjs/widgets/index.js +28 -0
  17. package/cjs/widgets/looking-similar/looking-similar.js +122 -0
  18. package/cjs/widgets/related-products/related-products.js +122 -0
  19. package/cjs/widgets/trending-items/trending-items.js +126 -0
  20. package/dist/instantsearch.development.d.ts +411 -12
  21. package/dist/instantsearch.development.js +1702 -265
  22. package/dist/instantsearch.development.js.map +1 -1
  23. package/dist/instantsearch.production.d.ts +411 -12
  24. package/dist/instantsearch.production.min.d.ts +411 -12
  25. package/dist/instantsearch.production.min.js +2 -2
  26. package/dist/instantsearch.production.min.js.map +1 -1
  27. package/es/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.d.ts +45 -0
  28. package/es/connectors/frequently-bought-together/connectFrequentlyBoughtTogether.js +86 -0
  29. package/es/connectors/index.d.ts +4 -0
  30. package/es/connectors/index.js +5 -1
  31. package/es/connectors/looking-similar/connectLookingSimilar.d.ts +49 -0
  32. package/es/connectors/looking-similar/connectLookingSimilar.js +87 -0
  33. package/es/connectors/related-products/connectRelatedProducts.d.ts +49 -0
  34. package/es/connectors/related-products/connectRelatedProducts.js +87 -0
  35. package/es/connectors/trending-items/connectTrendingItems.d.ts +57 -0
  36. package/es/connectors/trending-items/connectTrendingItems.js +83 -0
  37. package/es/lib/InstantSearch.d.ts +2 -0
  38. package/es/lib/InstantSearch.js +11 -2
  39. package/es/lib/server.d.ts +1 -1
  40. package/es/lib/server.js +28 -9
  41. package/es/lib/templating/renderTemplate.d.ts +1 -1
  42. package/es/lib/utils/addWidgetId.d.ts +3 -0
  43. package/es/lib/utils/addWidgetId.js +10 -0
  44. package/es/lib/utils/hydrateRecommendCache.d.ts +3 -0
  45. package/es/lib/utils/hydrateRecommendCache.js +17 -0
  46. package/es/lib/utils/hydrateSearchClient.js +7 -3
  47. package/es/lib/utils/index.d.ts +2 -0
  48. package/es/lib/utils/index.js +2 -0
  49. package/es/lib/utils/render-args.d.ts +3 -3
  50. package/es/lib/utils/render-args.js +3 -3
  51. package/es/lib/version.d.ts +1 -1
  52. package/es/lib/version.js +1 -1
  53. package/es/types/results.d.ts +7 -3
  54. package/es/types/templates.d.ts +1 -1
  55. package/es/types/widget.d.ts +16 -9
  56. package/es/widgets/frequently-bought-together/frequently-bought-together.d.ts +41 -0
  57. package/es/widgets/frequently-bought-together/frequently-bought-together.js +112 -0
  58. package/es/widgets/index/index.d.ts +2 -1
  59. package/es/widgets/index/index.js +89 -20
  60. package/es/widgets/index.d.ts +4 -0
  61. package/es/widgets/index.js +5 -1
  62. package/es/widgets/looking-similar/looking-similar.d.ts +41 -0
  63. package/es/widgets/looking-similar/looking-similar.js +114 -0
  64. package/es/widgets/related-products/related-products.d.ts +41 -0
  65. package/es/widgets/related-products/related-products.js +114 -0
  66. package/es/widgets/trending-items/trending-items.d.ts +41 -0
  67. package/es/widgets/trending-items/trending-items.js +118 -0
  68. package/package.json +7 -7
package/es/lib/server.js CHANGED
@@ -10,13 +10,14 @@ import { walkIndex } from "./utils/index.js";
10
10
  * in `getServerState()`.
11
11
  */
12
12
  export function waitForResults(search) {
13
+ var skipRecommend = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
13
14
  var helper = search.mainHelper;
14
15
 
15
16
  // Extract search parameters from the search client to use them
16
17
  // later during hydration.
17
18
  var requestParamsList;
18
19
  var client = helper.getClient();
19
- helper.setClient({
20
+ helper.setClient(_objectSpread(_objectSpread({}, client), {}, {
20
21
  search: function search(queries) {
21
22
  requestParamsList = queries.map(function (_ref) {
22
23
  var params = _ref.params;
@@ -24,13 +25,25 @@ export function waitForResults(search) {
24
25
  });
25
26
  return client.search(queries);
26
27
  }
27
- });
28
- helper.searchOnlyWithDerivedHelpers();
28
+ }));
29
+ search._hasSearchWidget && helper.searchOnlyWithDerivedHelpers();
30
+ !skipRecommend && search._hasRecommendWidget && helper.recommend();
29
31
  return new Promise(function (resolve, reject) {
32
+ var searchResultsReceived = !search._hasSearchWidget;
33
+ var recommendResultsReceived = !search._hasRecommendWidget || skipRecommend;
30
34
  // All derived helpers resolve in the same tick so we're safe only relying
31
35
  // on the first one.
32
36
  helper.derivedHelpers[0].on('result', function () {
33
- resolve(requestParamsList);
37
+ searchResultsReceived = true;
38
+ if (recommendResultsReceived) {
39
+ resolve(requestParamsList);
40
+ }
41
+ });
42
+ helper.derivedHelpers[0].on('recommend:result', function () {
43
+ recommendResultsReceived = true;
44
+ if (searchResultsReceived) {
45
+ resolve(requestParamsList);
46
+ }
34
47
  });
35
48
 
36
49
  // However, we listen to errors that can happen on any derived helper because
@@ -61,15 +74,21 @@ requestParamsList) {
61
74
  var initialResults = {};
62
75
  var requestParamsIndex = 0;
63
76
  walkIndex(rootIndex, function (widget) {
77
+ var _widget$getHelper;
64
78
  var searchResults = widget.getResults();
65
- if (searchResults) {
79
+ var recommendResults = (_widget$getHelper = widget.getHelper()) === null || _widget$getHelper === void 0 ? void 0 : _widget$getHelper.lastRecommendResults;
80
+ if (searchResults || recommendResults) {
66
81
  var requestParams = requestParamsList === null || requestParamsList === void 0 ? void 0 : requestParamsList[requestParamsIndex++];
67
- initialResults[widget.getIndexId()] = _objectSpread({
68
- // We convert the Helper state to a plain object to pass parsable data
69
- // structures from server to client.
82
+ initialResults[widget.getIndexId()] = _objectSpread(_objectSpread(_objectSpread({}, searchResults && {
70
83
  state: _objectSpread({}, searchResults._state),
71
84
  results: searchResults._rawResults
72
- }, requestParams && {
85
+ }), recommendResults && {
86
+ recommendResults: {
87
+ // We have to stringify + parse because of some explicitly undefined values.
88
+ params: JSON.parse(JSON.stringify(recommendResults._state.params)),
89
+ results: recommendResults._rawResults
90
+ }
91
+ }), requestParams && {
73
92
  requestParams: requestParams
74
93
  });
75
94
  }
@@ -9,4 +9,4 @@ export declare function renderTemplate({ templates, templateKey, compileOptions,
9
9
  data?: Record<string, any>;
10
10
  bindEvent?: BindEventForHits;
11
11
  sendEvent?: SendEventForHits;
12
- }): string | import("preact").VNode<{}> | import("preact").VNode<{}>[];
12
+ }): string | import("preact").VNode<{}> | import("preact").VNode<{}>[] | null;
@@ -0,0 +1,3 @@
1
+ import type { Widget } from '../../types';
2
+ export declare function addWidgetId(widget: Widget): void;
3
+ export declare function resetWidgetId(): void;
@@ -0,0 +1,10 @@
1
+ var id = 0;
2
+ export function addWidgetId(widget) {
3
+ if (widget.dependsOn !== 'recommend') {
4
+ return;
5
+ }
6
+ widget.$$id = id++;
7
+ }
8
+ export function resetWidgetId() {
9
+ id = 0;
10
+ }
@@ -0,0 +1,3 @@
1
+ import type { InitialResults } from '../../types';
2
+ import type { AlgoliaSearchHelper } from 'algoliasearch-helper';
3
+ export declare function hydrateRecommendCache(helper: AlgoliaSearchHelper, initialResults: InitialResults): void;
@@ -0,0 +1,17 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
6
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
7
+ export function hydrateRecommendCache(helper, initialResults) {
8
+ var recommendCache = Object.keys(initialResults).reduce(function (acc, indexName) {
9
+ var initialResult = initialResults[indexName];
10
+ if (initialResult.recommendResults) {
11
+ // @MAJOR: Use `Object.assign` instead of spread operator
12
+ return _objectSpread(_objectSpread({}, acc), initialResult.recommendResults.results);
13
+ }
14
+ return acc;
15
+ }, {});
16
+ helper._recommendCache = recommendCache;
17
+ }
@@ -27,16 +27,20 @@ export function hydrateSearchClient(client, results) {
27
27
  state = _results$key.state,
28
28
  requestParams = _results$key.requestParams,
29
29
  serverResults = _results$key.results;
30
- return serverResults.map(function (result) {
30
+ return serverResults && state ? serverResults.map(function (result) {
31
31
  return _objectSpread({
32
32
  indexName: state.index || result.index
33
33
  }, requestParams || result.params ? {
34
34
  params: serializeQueryParameters(requestParams || deserializeQueryParameters(result.params))
35
35
  } : {});
36
- });
36
+ }) : [];
37
37
  });
38
38
  var cachedResults = Object.keys(results).reduce(function (acc, key) {
39
- return acc.concat(results[key].results);
39
+ var res = results[key].results;
40
+ if (!res) {
41
+ return acc;
42
+ }
43
+ return acc.concat(res);
40
44
  }, []);
41
45
 
42
46
  // Algoliasearch API Client >= v4
@@ -1,3 +1,4 @@
1
+ export * from './addWidgetId';
1
2
  export * from './capitalize';
2
3
  export * from './checkIndexUiState';
3
4
  export * from './checkRendering';
@@ -27,6 +28,7 @@ export * from './getRefinements';
27
28
  export * from './getWidgetAttribute';
28
29
  export * from './hits-absolute-position';
29
30
  export * from './hits-query-id';
31
+ export * from './hydrateRecommendCache';
30
32
  export * from './hydrateSearchClient';
31
33
  export * from './isDomElement';
32
34
  export * from './isEqual';
@@ -1,3 +1,4 @@
1
+ export * from "./addWidgetId.js";
1
2
  export * from "./capitalize.js";
2
3
  export * from "./checkIndexUiState.js";
3
4
  export * from "./checkRendering.js";
@@ -27,6 +28,7 @@ export * from "./getRefinements.js";
27
28
  export * from "./getWidgetAttribute.js";
28
29
  export * from "./hits-absolute-position.js";
29
30
  export * from "./hits-query-id.js";
31
+ export * from "./hydrateRecommendCache.js";
30
32
  export * from "./hydrateSearchClient.js";
31
33
  export * from "./isDomElement.js";
32
34
  export * from "./isEqual.js";
@@ -1,4 +1,4 @@
1
- import type { InstantSearch, UiState } from '../../types';
1
+ import type { InstantSearch, UiState, Widget } from '../../types';
2
2
  import type { IndexWidget } from '../../widgets/index/index';
3
3
  export declare function createInitArgs(instantSearchInstance: InstantSearch, parent: IndexWidget, uiState: UiState): {
4
4
  uiState: UiState;
@@ -126,11 +126,11 @@ export declare function createInitArgs(instantSearchInstance: InstantSearch, par
126
126
  status: import("../InstantSearch").InstantSearchStatus;
127
127
  error: Error | undefined;
128
128
  };
129
- export declare function createRenderArgs(instantSearchInstance: InstantSearch, parent: IndexWidget): {
129
+ export declare function createRenderArgs(instantSearchInstance: InstantSearch, parent: IndexWidget, widget: IndexWidget | Widget): {
130
130
  helper: import("algoliasearch-helper").AlgoliaSearchHelper;
131
131
  parent: IndexWidget;
132
132
  instantSearchInstance: InstantSearch<UiState, UiState>;
133
- results: import("algoliasearch-helper").SearchResults<any>;
133
+ results: import("algoliasearch-helper").SearchResults<any> | import("algoliasearch-helper").RecommendResultItem;
134
134
  scopedResults: import("../../types").ScopedResult[];
135
135
  state: import("algoliasearch-helper").SearchParameters;
136
136
  renderState: import("../../types").RenderState;
@@ -17,8 +17,8 @@ export function createInitArgs(instantSearchInstance, parent, uiState) {
17
17
  error: instantSearchInstance.error
18
18
  };
19
19
  }
20
- export function createRenderArgs(instantSearchInstance, parent) {
21
- var results = parent.getResults();
20
+ export function createRenderArgs(instantSearchInstance, parent, widget) {
21
+ var results = parent.getResultsForWidget(widget);
22
22
  var helper = parent.getHelper();
23
23
  return {
24
24
  helper: helper,
@@ -26,7 +26,7 @@ export function createRenderArgs(instantSearchInstance, parent) {
26
26
  instantSearchInstance: instantSearchInstance,
27
27
  results: results,
28
28
  scopedResults: parent.getScopedResults(),
29
- state: results ? results._state : helper.state,
29
+ state: results && '_state' in results ? results._state : helper.state,
30
30
  renderState: instantSearchInstance.renderState,
31
31
  templatesConfig: instantSearchInstance.templatesConfig,
32
32
  createURL: parent.createURL,
@@ -1,2 +1,2 @@
1
- declare const _default: "4.68.1";
1
+ declare const _default: "4.70.0";
2
2
  export default _default;
package/es/lib/version.js CHANGED
@@ -1 +1 @@
1
- export default '4.68.1';
1
+ export default '4.70.0';
@@ -1,5 +1,5 @@
1
1
  import type { SearchOptions } from './algoliasearch';
2
- import type { PlainSearchParameters, SearchForFacetValues, SearchResults } from 'algoliasearch-helper';
2
+ import type { PlainSearchParameters, RecommendParametersOptions, RecommendResults, SearchForFacetValues, SearchResults } from 'algoliasearch-helper';
3
3
  export type HitAttributeHighlightResult = {
4
4
  value: string;
5
5
  matchLevel: 'none' | 'partial' | 'full';
@@ -65,8 +65,12 @@ export type NumericRefinement = {
65
65
  };
66
66
  export type Refinement = FacetRefinement | NumericRefinement;
67
67
  type InitialResult = {
68
- state: PlainSearchParameters;
69
- results: SearchResults['_rawResults'];
68
+ state?: PlainSearchParameters;
69
+ results?: SearchResults['_rawResults'];
70
+ recommendResults?: {
71
+ params: RecommendParametersOptions['params'];
72
+ results: RecommendResults['_rawResults'];
73
+ };
70
74
  requestParams?: SearchOptions;
71
75
  };
72
76
  export type InitialResults = Record<string, InitialResult>;
@@ -2,7 +2,7 @@ import type { Highlight, ReverseHighlight, ReverseSnippet, Snippet } from '../he
2
2
  import type { BuiltInBindEventForHits, CustomBindEventForHits, SendEventForHits } from '../lib/utils';
3
3
  import type { html } from 'htm/preact';
4
4
  import type { VNode } from 'preact';
5
- export type Template<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string);
5
+ export type Template<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string | null);
6
6
  export type TemplateParams = {
7
7
  html: typeof html;
8
8
  components: {
@@ -3,7 +3,7 @@ import type { InstantSearch } from './instantsearch';
3
3
  import type { IndexRenderState, WidgetRenderState } from './render-state';
4
4
  import type { IndexUiState, UiState } from './ui-state';
5
5
  import type { Expand, RequiredKeys } from './utils';
6
- import type { AlgoliaSearchHelper as Helper, SearchParameters, SearchResults, RecommendParameters } from 'algoliasearch-helper';
6
+ import type { AlgoliaSearchHelper as Helper, SearchParameters, SearchResults, RecommendParameters, RecommendResultItem } from 'algoliasearch-helper';
7
7
  export type ScopedResult = {
8
8
  indexId: string;
9
9
  results: SearchResults;
@@ -39,10 +39,11 @@ export type RenderOptions = SharedRenderOptions & {
39
39
  export type DisposeOptions = {
40
40
  helper: Helper;
41
41
  state: SearchParameters;
42
+ recommendState: RecommendParameters;
42
43
  parent: IndexWidget;
43
44
  };
44
- export type BuiltinTypes = 'ais.analytics' | 'ais.answers' | 'ais.autocomplete' | 'ais.breadcrumb' | 'ais.clearRefinements' | 'ais.configure' | 'ais.configureRelatedItems' | 'ais.currentRefinements' | 'ais.dynamicWidgets' | 'ais.geoSearch' | 'ais.hierarchicalMenu' | 'ais.hits' | 'ais.hitsPerPage' | 'ais.index' | 'ais.infiniteHits' | 'ais.menu' | 'ais.numericMenu' | 'ais.pagination' | 'ais.places' | 'ais.poweredBy' | 'ais.queryRules' | 'ais.range' | 'ais.rangeSlider' | 'ais.rangeInput' | 'ais.ratingMenu' | 'ais.refinementList' | 'ais.searchBox' | 'ais.relevantSort' | 'ais.sortBy' | 'ais.stats' | 'ais.toggleRefinement' | 'ais.voiceSearch';
45
- export type BuiltinWidgetTypes = 'ais.analytics' | 'ais.answers' | 'ais.autocomplete' | 'ais.breadcrumb' | 'ais.clearRefinements' | 'ais.configure' | 'ais.configureRelatedItems' | 'ais.currentRefinements' | 'ais.dynamicWidgets' | 'ais.geoSearch' | 'ais.hierarchicalMenu' | 'ais.hits' | 'ais.hitsPerPage' | 'ais.index' | 'ais.infiniteHits' | 'ais.menu' | 'ais.menuSelect' | 'ais.numericMenu' | 'ais.pagination' | 'ais.places' | 'ais.poweredBy' | 'ais.queryRuleCustomData' | 'ais.queryRuleContext' | 'ais.rangeInput' | 'ais.rangeSlider' | 'ais.ratingMenu' | 'ais.refinementList' | 'ais.searchBox' | 'ais.relevantSort' | 'ais.sortBy' | 'ais.stats' | 'ais.toggleRefinement' | 'ais.voiceSearch';
45
+ export type BuiltinTypes = 'ais.analytics' | 'ais.answers' | 'ais.autocomplete' | 'ais.breadcrumb' | 'ais.clearRefinements' | 'ais.configure' | 'ais.configureRelatedItems' | 'ais.currentRefinements' | 'ais.dynamicWidgets' | 'ais.frequentlyBoughtTogether' | 'ais.geoSearch' | 'ais.hierarchicalMenu' | 'ais.hits' | 'ais.hitsPerPage' | 'ais.index' | 'ais.infiniteHits' | 'ais.lookingSimilar' | 'ais.menu' | 'ais.numericMenu' | 'ais.pagination' | 'ais.places' | 'ais.poweredBy' | 'ais.queryRules' | 'ais.range' | 'ais.rangeSlider' | 'ais.rangeInput' | 'ais.ratingMenu' | 'ais.refinementList' | 'ais.relatedProducts' | 'ais.searchBox' | 'ais.relevantSort' | 'ais.sortBy' | 'ais.stats' | 'ais.toggleRefinement' | 'ais.trendingItems' | 'ais.voiceSearch';
46
+ export type BuiltinWidgetTypes = 'ais.analytics' | 'ais.answers' | 'ais.autocomplete' | 'ais.breadcrumb' | 'ais.clearRefinements' | 'ais.configure' | 'ais.configureRelatedItems' | 'ais.currentRefinements' | 'ais.dynamicWidgets' | 'ais.frequentlyBoughtTogether' | 'ais.geoSearch' | 'ais.hierarchicalMenu' | 'ais.hits' | 'ais.hitsPerPage' | 'ais.index' | 'ais.infiniteHits' | 'ais.lookingSimilar' | 'ais.menu' | 'ais.menuSelect' | 'ais.numericMenu' | 'ais.pagination' | 'ais.places' | 'ais.poweredBy' | 'ais.queryRuleCustomData' | 'ais.queryRuleContext' | 'ais.rangeInput' | 'ais.rangeSlider' | 'ais.ratingMenu' | 'ais.refinementList' | 'ais.relatedProducts' | 'ais.searchBox' | 'ais.relevantSort' | 'ais.sortBy' | 'ais.stats' | 'ais.toggleRefinement' | 'ais.trendingItems' | 'ais.voiceSearch';
46
47
  export type UnknownWidgetParams = NonNullable<object>;
47
48
  export type WidgetParams = {
48
49
  widgetParams?: UnknownWidgetParams;
@@ -54,17 +55,23 @@ export type WidgetDescription = {
54
55
  indexRenderState?: Record<string, unknown>;
55
56
  indexUiState?: Record<string, unknown>;
56
57
  };
57
- type SearchWidgetLifeCycle<TWidgetDescription extends WidgetDescription> = {
58
+ type SearchWidget<TWidgetDescription extends WidgetDescription> = {
58
59
  dependsOn?: 'search';
59
60
  getWidgetParameters?: (state: SearchParameters, widgetParametersOptions: {
60
61
  uiState: Expand<Partial<TWidgetDescription['indexUiState'] & IndexUiState>>;
61
62
  }) => SearchParameters;
62
63
  };
63
- type RecommendWidgetLifeCycle<TWidgetDescription extends WidgetDescription> = {
64
- dependsOn?: 'recommend';
64
+ type RecommendRenderOptions = SharedRenderOptions & {
65
+ results: RecommendResultItem;
66
+ };
67
+ type RecommendWidget<TWidgetDescription extends WidgetDescription & WidgetParams> = {
68
+ dependsOn: 'recommend';
69
+ $$id?: number;
65
70
  getWidgetParameters: (state: RecommendParameters, widgetParametersOptions: {
66
71
  uiState: Expand<Partial<TWidgetDescription['indexUiState'] & IndexUiState>>;
67
72
  }) => RecommendParameters;
73
+ getRenderState: (renderState: Expand<IndexRenderState & Partial<TWidgetDescription['indexRenderState']>>, renderOptions: InitOptions | RecommendRenderOptions) => IndexRenderState & TWidgetDescription['indexRenderState'];
74
+ getWidgetRenderState: (renderOptions: InitOptions | RecommendRenderOptions) => Expand<WidgetRenderState<TWidgetDescription['renderState'], TWidgetDescription['widgetParams']>>;
68
75
  };
69
76
  type RequiredWidgetLifeCycle<TWidgetDescription extends WidgetDescription> = {
70
77
  /**
@@ -87,7 +94,7 @@ type RequiredWidgetLifeCycle<TWidgetDescription extends WidgetDescription> = {
87
94
  * Called when this widget is unmounted. Used to remove refinements set by
88
95
  * during this widget's initialization and life time.
89
96
  */
90
- dispose?: (options: DisposeOptions) => SearchParameters | void;
97
+ dispose?: (options: DisposeOptions) => SearchParameters | RecommendParameters | void;
91
98
  };
92
99
  type RequiredWidgetType<TWidgetDescription extends WidgetDescription> = {
93
100
  /**
@@ -135,7 +142,7 @@ type RequiredUiStateLifeCycle<TWidgetDescription extends WidgetDescription> = {
135
142
  getWidgetSearchParameters: (state: SearchParameters, widgetSearchParametersOptions: {
136
143
  uiState: Expand<Partial<TWidgetDescription['indexUiState'] & IndexUiState>>;
137
144
  }) => SearchParameters;
138
- } & (SearchWidgetLifeCycle<TWidgetDescription> | RecommendWidgetLifeCycle<TWidgetDescription>);
145
+ };
139
146
  type UiStateLifeCycle<TWidgetDescription extends WidgetDescription> = TWidgetDescription extends RequiredKeys<WidgetDescription, 'indexUiState'> ? RequiredUiStateLifeCycle<TWidgetDescription> : Partial<RequiredUiStateLifeCycle<TWidgetDescription>>;
140
147
  type RequiredRenderStateLifeCycle<TWidgetDescription extends WidgetDescription & WidgetParams> = {
141
148
  /**
@@ -151,7 +158,7 @@ type RequiredRenderStateLifeCycle<TWidgetDescription extends WidgetDescription &
151
158
  type RenderStateLifeCycle<TWidgetDescription extends WidgetDescription & WidgetParams> = TWidgetDescription extends RequiredKeys<WidgetDescription, 'renderState' | 'indexRenderState'> & WidgetParams ? RequiredRenderStateLifeCycle<TWidgetDescription> : Partial<RequiredRenderStateLifeCycle<TWidgetDescription>>;
152
159
  export type Widget<TWidgetDescription extends WidgetDescription & WidgetParams = {
153
160
  $$type: string;
154
- }> = Expand<RequiredWidgetLifeCycle<TWidgetDescription> & WidgetType<TWidgetDescription> & UiStateLifeCycle<TWidgetDescription> & RenderStateLifeCycle<TWidgetDescription>>;
161
+ }> = Expand<RequiredWidgetLifeCycle<TWidgetDescription> & WidgetType<TWidgetDescription> & UiStateLifeCycle<TWidgetDescription> & RenderStateLifeCycle<TWidgetDescription>> & (SearchWidget<TWidgetDescription> | RecommendWidget<TWidgetDescription>);
155
162
  export type TransformItemsMetadata = {
156
163
  results?: SearchResults;
157
164
  };
@@ -0,0 +1,41 @@
1
+
2
+ import type { FrequentlyBoughtTogetherWidgetDescription, FrequentlyBoughtTogetherConnectorParams } from '../../connectors/frequently-bought-together/connectFrequentlyBoughtTogether';
3
+ import type { Template, WidgetFactory, Hit } from '../../types';
4
+ import type { RecommendResultItem } from 'algoliasearch-helper';
5
+ import type { RecommendClassNames, FrequentlyBoughtTogetherProps as FrequentlyBoughtTogetherUiProps } from 'instantsearch-ui-components';
6
+ export type FrequentlyBoughtTogetherCSSClasses = Partial<RecommendClassNames>;
7
+ export type FrequentlyBoughtTogetherTemplates = Partial<{
8
+ /**
9
+ * Template to use when there are no results.
10
+ */
11
+ empty: Template<RecommendResultItem>;
12
+ /**
13
+ * Template to use for the header of the widget.
14
+ */
15
+ header: Template<Pick<Parameters<NonNullable<FrequentlyBoughtTogetherUiProps<Hit>['headerComponent']>>[0], 'items'> & {
16
+ cssClasses: RecommendClassNames;
17
+ }>;
18
+ /**
19
+ * Template to use for each result. This template will receive an object containing a single record.
20
+ */
21
+ item: Template<Hit>;
22
+ }>;
23
+ type FrequentlyBoughtTogetherWidgetParams = {
24
+ /**
25
+ * CSS Selector or HTMLElement to insert the widget.
26
+ */
27
+ container: string | HTMLElement;
28
+ /**
29
+ * Templates to use for the widget.
30
+ */
31
+ templates?: FrequentlyBoughtTogetherTemplates;
32
+ /**
33
+ * CSS classes to add.
34
+ */
35
+ cssClasses?: FrequentlyBoughtTogetherCSSClasses;
36
+ };
37
+ export type FrequentlyBoughtTogetherWidget = WidgetFactory<FrequentlyBoughtTogetherWidgetDescription & {
38
+ $$widgetType: 'ais.frequentlyBoughtTogether';
39
+ }, FrequentlyBoughtTogetherConnectorParams, FrequentlyBoughtTogetherWidgetParams>;
40
+ declare const frequentlyBoughtTogether: FrequentlyBoughtTogetherWidget;
41
+ export default frequentlyBoughtTogether;
@@ -0,0 +1,112 @@
1
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
2
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
4
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
5
+ function _toPropertyKey(arg) { var key = _toPrimitive(arg, "string"); return _typeof(key) === "symbol" ? key : String(key); }
6
+ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input === null) return input; var prim = input[Symbol.toPrimitive]; if (prim !== undefined) { var res = prim.call(input, hint || "default"); if (_typeof(res) !== "object") return res; throw new TypeError("@@toPrimitive must return a primitive value."); } return (hint === "string" ? String : Number)(input); }
7
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
8
+ import { createFrequentlyBoughtTogetherComponent } from 'instantsearch-ui-components';
9
+ import { Fragment, h, render } from 'preact';
10
+ import TemplateComponent from "../../components/Template/Template.js";
11
+ import connectFrequentlyBoughtTogether from "../../connectors/frequently-bought-together/connectFrequentlyBoughtTogether.js";
12
+ import { prepareTemplateProps } from "../../lib/templating/index.js";
13
+ import { getContainerNode, createDocumentationMessageGenerator } from "../../lib/utils/index.js";
14
+ var withUsage = createDocumentationMessageGenerator({
15
+ name: 'frequently-bought-together'
16
+ });
17
+ var FrequentlyBoughtTogether = createFrequentlyBoughtTogetherComponent({
18
+ createElement: h,
19
+ Fragment: Fragment
20
+ });
21
+ var renderer = function renderer(_ref) {
22
+ var renderState = _ref.renderState,
23
+ cssClasses = _ref.cssClasses,
24
+ containerNode = _ref.containerNode,
25
+ templates = _ref.templates;
26
+ return function (_ref2, isFirstRendering) {
27
+ var items = _ref2.items,
28
+ results = _ref2.results,
29
+ instantSearchInstance = _ref2.instantSearchInstance;
30
+ if (isFirstRendering) {
31
+ renderState.templateProps = prepareTemplateProps({
32
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
33
+ defaultTemplates: {},
34
+ templatesConfig: instantSearchInstance.templatesConfig,
35
+ templates: templates
36
+ });
37
+ return;
38
+ }
39
+ var headerComponent = templates.header ? function (data) {
40
+ return h(TemplateComponent, _extends({}, renderState.templateProps, {
41
+ templateKey: "header",
42
+ rootTagName: "fragment",
43
+ data: {
44
+ cssClasses: data.classNames,
45
+ items: data.items
46
+ }
47
+ }));
48
+ } : undefined;
49
+ var itemComponent = templates.item ? function (_ref3) {
50
+ var item = _ref3.item;
51
+ return h(TemplateComponent, _extends({}, renderState.templateProps, {
52
+ templateKey: "item",
53
+ rootTagName: "fragment",
54
+ data: item
55
+ }));
56
+ } : undefined;
57
+ var emptyComponent = templates.empty ? function () {
58
+ return h(TemplateComponent, _extends({}, renderState.templateProps, {
59
+ templateKey: "empty",
60
+ rootTagName: "fragment",
61
+ data: results
62
+ }));
63
+ } : undefined;
64
+ render(h(FrequentlyBoughtTogether, {
65
+ items: items,
66
+ headerComponent: headerComponent,
67
+ itemComponent: itemComponent,
68
+ sendEvent: function sendEvent() {},
69
+ classNames: cssClasses,
70
+ emptyComponent: emptyComponent,
71
+ status: instantSearchInstance.status
72
+ }), containerNode);
73
+ };
74
+ };
75
+ var frequentlyBoughtTogether = function frequentlyBoughtTogether(widgetParams) {
76
+ var _ref4 = widgetParams || {},
77
+ container = _ref4.container,
78
+ objectIDs = _ref4.objectIDs,
79
+ limit = _ref4.limit,
80
+ queryParameters = _ref4.queryParameters,
81
+ threshold = _ref4.threshold,
82
+ escapeHTML = _ref4.escapeHTML,
83
+ transformItems = _ref4.transformItems,
84
+ _ref4$templates = _ref4.templates,
85
+ templates = _ref4$templates === void 0 ? {} : _ref4$templates,
86
+ _ref4$cssClasses = _ref4.cssClasses,
87
+ cssClasses = _ref4$cssClasses === void 0 ? {} : _ref4$cssClasses;
88
+ if (!container) {
89
+ throw new Error(withUsage('The `container` option is required.'));
90
+ }
91
+ var containerNode = getContainerNode(container);
92
+ var specializedRenderer = renderer({
93
+ containerNode: containerNode,
94
+ cssClasses: cssClasses,
95
+ renderState: {},
96
+ templates: templates
97
+ });
98
+ var makeWidget = connectFrequentlyBoughtTogether(specializedRenderer, function () {
99
+ return render(null, containerNode);
100
+ });
101
+ return _objectSpread(_objectSpread({}, makeWidget({
102
+ objectIDs: objectIDs,
103
+ limit: limit,
104
+ queryParameters: queryParameters,
105
+ threshold: threshold,
106
+ escapeHTML: escapeHTML,
107
+ transformItems: transformItems
108
+ })), {}, {
109
+ $$widgetType: 'ais.frequentlyBoughtTogether'
110
+ });
111
+ };
112
+ export default frequentlyBoughtTogether;
@@ -1,5 +1,5 @@
1
1
  import type { InstantSearch, UiState, IndexUiState, Widget, ScopedResult } from '../../types';
2
- import type { AlgoliaSearchHelper as Helper, SearchParameters, SearchResults } from 'algoliasearch-helper';
2
+ import type { AlgoliaSearchHelper as Helper, SearchParameters, SearchResults, RecommendResultItem } from 'algoliasearch-helper';
3
3
  export type IndexWidgetParams = {
4
4
  indexName: string;
5
5
  indexId?: string;
@@ -23,6 +23,7 @@ export type IndexWidget<TUiState extends UiState = UiState> = Omit<Widget<IndexW
23
23
  getIndexId: () => string;
24
24
  getHelper: () => Helper | null;
25
25
  getResults: () => SearchResults | null;
26
+ getResultsForWidget: (widget: IndexWidget | Widget) => SearchResults | RecommendResultItem | null;
26
27
  getPreviousState: () => SearchParameters | null;
27
28
  getScopedResults: () => ScopedResult[];
28
29
  getParent: () => IndexWidget | null;