instantsearch.js 4.55.0 → 4.56.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 (62) hide show
  1. package/cjs/components/Breadcrumb/Breadcrumb.js +2 -2
  2. package/cjs/components/RangeInput/RangeInput.js +22 -11
  3. package/cjs/components/RefinementList/RefinementList.js +34 -52
  4. package/cjs/components/Slider/Rheostat.js +163 -249
  5. package/cjs/connectors/infinite-hits/connectInfiniteHits.js +22 -7
  6. package/cjs/lib/InstantSearch.js +2 -4
  7. package/cjs/lib/routers/history.js +54 -1
  8. package/cjs/lib/utils/render-args.js +3 -2
  9. package/cjs/lib/version.js +1 -1
  10. package/cjs/widgets/hits-per-page/hits-per-page.js +3 -1
  11. package/cjs/widgets/index/index.js +8 -8
  12. package/dist/instantsearch.development.d.ts +76 -76
  13. package/dist/instantsearch.development.js +345 -341
  14. package/dist/instantsearch.development.js.map +1 -1
  15. package/dist/instantsearch.production.d.ts +76 -76
  16. package/dist/instantsearch.production.min.d.ts +76 -76
  17. package/dist/instantsearch.production.min.js +2 -2
  18. package/dist/instantsearch.production.min.js.map +1 -1
  19. package/es/components/Breadcrumb/Breadcrumb.d.ts +2 -2
  20. package/es/components/Breadcrumb/Breadcrumb.js +2 -2
  21. package/es/components/GeoSearchControls/GeoSearchButton.d.ts +1 -1
  22. package/es/components/GeoSearchControls/GeoSearchControls.d.ts +3 -3
  23. package/es/components/GeoSearchControls/GeoSearchToggle.d.ts +1 -1
  24. package/es/components/Pagination/Pagination.d.ts +2 -2
  25. package/es/components/RangeInput/RangeInput.d.ts +7 -4
  26. package/es/components/RangeInput/RangeInput.js +22 -11
  27. package/es/components/RefinementList/RefinementList.d.ts +0 -1
  28. package/es/components/RefinementList/RefinementList.js +34 -52
  29. package/es/components/RelevantSort/RelevantSort.d.ts +1 -1
  30. package/es/components/Selector/Selector.d.ts +2 -2
  31. package/es/components/Slider/Rheostat.d.ts +23 -17
  32. package/es/components/Slider/Rheostat.js +163 -249
  33. package/es/components/Slider/Slider.d.ts +1 -1
  34. package/es/connectors/current-refinements/connectCurrentRefinements.d.ts +2 -2
  35. package/es/connectors/dynamic-widgets/connectDynamicWidgets.d.ts +2 -2
  36. package/es/connectors/geo-search/connectGeoSearch.d.ts +7 -7
  37. package/es/connectors/infinite-hits/connectInfiniteHits.js +23 -8
  38. package/es/connectors/menu/connectMenu.d.ts +2 -2
  39. package/es/connectors/pagination/connectPagination.d.ts +1 -1
  40. package/es/connectors/range/connectRange.d.ts +3 -3
  41. package/es/connectors/refinement-list/connectRefinementList.d.ts +3 -3
  42. package/es/connectors/relevant-sort/connectRelevantSort.d.ts +1 -1
  43. package/es/lib/InstantSearch.d.ts +13 -13
  44. package/es/lib/InstantSearch.js +3 -5
  45. package/es/lib/routers/history.d.ts +2 -2
  46. package/es/lib/routers/history.js +55 -2
  47. package/es/lib/utils/defer.d.ts +2 -2
  48. package/es/lib/utils/render-args.js +3 -2
  49. package/es/lib/version.d.ts +1 -1
  50. package/es/lib/version.js +1 -1
  51. package/es/types/middleware.d.ts +6 -6
  52. package/es/types/router.d.ts +7 -7
  53. package/es/types/widget.d.ts +1 -1
  54. package/es/widgets/dynamic-widgets/dynamic-widgets.d.ts +2 -2
  55. package/es/widgets/geo-search/createHTMLMarker.d.ts +1 -1
  56. package/es/widgets/geo-search/geo-search.d.ts +1 -1
  57. package/es/widgets/hits-per-page/hits-per-page.js +3 -1
  58. package/es/widgets/index/index.d.ts +20 -20
  59. package/es/widgets/index/index.js +8 -8
  60. package/es/widgets/panel/panel.d.ts +2 -2
  61. package/es/widgets/range-slider/range-slider.d.ts +1 -1
  62. package/package.json +6 -6
@@ -171,6 +171,7 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
171
171
  });
172
172
  isFirstPage = state.page === undefined || getFirstReceivedPage(state, cachedHits) === 0;
173
173
  } else {
174
+ var _results$disjunctiveF, _results$facets, _results$hierarchical;
174
175
  var _state$page3 = state.page,
175
176
  _page = _state$page3 === void 0 ? 0 : _state$page3;
176
177
  if (escapeHTML && results.hits.length > 0) {
@@ -181,7 +182,21 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
181
182
  var transformedHits = transformItems(hitsWithAbsolutePositionAndQueryID, {
182
183
  results: results
183
184
  });
184
- if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle') {
185
+
186
+ /*
187
+ With dynamic widgets, facets are not included in the state before their relevant widgets are mounted. Until then, we need to bail out of writing this incomplete state representation in cache.
188
+ */
189
+ var hasDynamicWidgets = false;
190
+ (0, _utils.walkIndex)(instantSearchInstance.mainIndex, function (indexWidget) {
191
+ if (!hasDynamicWidgets && indexWidget.getWidgets().some(function (_ref7) {
192
+ var $$type = _ref7.$$type;
193
+ return $$type === 'ais.dynamicWidgets';
194
+ })) {
195
+ hasDynamicWidgets = true;
196
+ }
197
+ });
198
+ var hasNoFacets = !((_results$disjunctiveF = results.disjunctiveFacets) !== null && _results$disjunctiveF !== void 0 && _results$disjunctiveF.length) && !((_results$facets = results.facets) !== null && _results$facets !== void 0 && _results$facets.length) && !((_results$hierarchical = results.hierarchicalFacets) !== null && _results$hierarchical !== void 0 && _results$hierarchical.length);
199
+ if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle' && !(hasDynamicWidgets && hasNoFacets)) {
185
200
  cachedHits[_page] = transformedHits;
186
201
  cache.write({
187
202
  state: normalizeState(state),
@@ -206,8 +221,8 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
206
221
  widgetParams: widgetParams
207
222
  };
208
223
  },
209
- dispose: function dispose(_ref7) {
210
- var state = _ref7.state;
224
+ dispose: function dispose(_ref8) {
225
+ var state = _ref8.state;
211
226
  unmountFn();
212
227
  var stateWithoutPage = state.setQueryParameter('page', undefined);
213
228
  if (!escapeHTML) {
@@ -217,8 +232,8 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
217
232
  return _objectSpread(_objectSpread({}, acc), {}, _defineProperty({}, key, undefined));
218
233
  }, {}));
219
234
  },
220
- getWidgetUiState: function getWidgetUiState(uiState, _ref8) {
221
- var searchParameters = _ref8.searchParameters;
235
+ getWidgetUiState: function getWidgetUiState(uiState, _ref9) {
236
+ var searchParameters = _ref9.searchParameters;
222
237
  var page = searchParameters.page || 0;
223
238
  if (!page) {
224
239
  // return without adding `page` to uiState
@@ -231,8 +246,8 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
231
246
  page: page + 1
232
247
  });
233
248
  },
234
- getWidgetSearchParameters: function getWidgetSearchParameters(searchParameters, _ref9) {
235
- var uiState = _ref9.uiState;
249
+ getWidgetSearchParameters: function getWidgetSearchParameters(searchParameters, _ref10) {
250
+ var uiState = _ref10.uiState;
236
251
  var widgetSearchParameters = searchParameters;
237
252
  if (escapeHTML) {
238
253
  widgetSearchParameters = searchParameters.setQueryParameters(_utils.TAG_PLACEHOLDER);
@@ -107,7 +107,7 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
107
107
  }));
108
108
  _this.setMaxListeners(100);
109
109
  var _options$indexName = options.indexName,
110
- indexName = _options$indexName === void 0 ? null : _options$indexName,
110
+ indexName = _options$indexName === void 0 ? '' : _options$indexName,
111
111
  numberLocale = options.numberLocale,
112
112
  _options$initialUiSta = options.initialUiState,
113
113
  initialUiState = _options$initialUiSta === void 0 ? {} : _options$initialUiSta,
@@ -124,9 +124,6 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
124
124
  insightsClient = _options$insightsClie === void 0 ? null : _options$insightsClie,
125
125
  _options$onStateChang = options.onStateChange,
126
126
  onStateChange = _options$onStateChang === void 0 ? null : _options$onStateChang;
127
- if (indexName === null) {
128
- throw new Error(withUsage('The `indexName` option is required.'));
129
- }
130
127
  if (searchClient === null) {
131
128
  throw new Error(withUsage('The `searchClient` option is required.'));
132
129
  }
@@ -368,6 +365,7 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
368
365
  mainHelper.search = function () {
369
366
  _this3.status = 'loading';
370
367
  _this3.scheduleRender(false);
368
+ process.env.NODE_ENV === 'development' ? (0, _utils.warning)(Boolean(_this3.indexName) || _this3.mainIndex.getWidgets().some(_utils.isIndexWidget), 'No indexName provided, nor an explicit index widget in the widgets tree. This is required to be able to display results.') : void 0;
371
369
 
372
370
  // This solution allows us to keep the exact same API for the users but
373
371
  // under the hood, we have a different implementation. It should be
@@ -22,6 +22,48 @@ var setWindowTitle = function setWindowTitle(title) {
22
22
  }
23
23
  };
24
24
  var BrowserHistory = /*#__PURE__*/function () {
25
+ /**
26
+ * Transforms a UI state into a title for the page.
27
+ */
28
+
29
+ /**
30
+ * Time in milliseconds before performing a write in the history.
31
+ * It prevents from adding too many entries in the history and
32
+ * makes the back button more usable.
33
+ *
34
+ * @default 400
35
+ */
36
+
37
+ /**
38
+ * Creates a full URL based on the route state.
39
+ * The storage adaptor maps all syncable keys to the query string of the URL.
40
+ */
41
+
42
+ /**
43
+ * Parses the URL into a route state.
44
+ * It should be symmetrical to `createURL`.
45
+ */
46
+
47
+ /**
48
+ * Returns the location to store in the history.
49
+ * @default () => window.location
50
+ */
51
+
52
+ /**
53
+ * Indicates if last action was back/forward in the browser.
54
+ */
55
+
56
+ /**
57
+ * Indicates whether the history router is disposed or not.
58
+ */
59
+
60
+ /**
61
+ * Indicates the window.history.length before the last call to
62
+ * window.history.pushState (called in `write`).
63
+ * It allows to determine if a `pushState` has been triggered elsewhere,
64
+ * and thus to prevent the `write` method from calling `pushState`.
65
+ */
66
+
25
67
  /**
26
68
  * Initializes a new storage provider that syncs the search state to the URL
27
69
  * using web APIs (`window.location.pushState` and `onpopstate` event).
@@ -45,6 +87,7 @@ var BrowserHistory = /*#__PURE__*/function () {
45
87
  _defineProperty(this, "parseURL", void 0);
46
88
  _defineProperty(this, "getLocation", void 0);
47
89
  _defineProperty(this, "writeTimer", void 0);
90
+ _defineProperty(this, "_onPopState", void 0);
48
91
  _defineProperty(this, "inPopState", false);
49
92
  _defineProperty(this, "isDisposed", false);
50
93
  _defineProperty(this, "latestAcknowledgedHistory", 0);
@@ -150,11 +193,21 @@ var BrowserHistory = /*#__PURE__*/function () {
150
193
  }, {
151
194
  key: "createURL",
152
195
  value: function createURL(routeState) {
153
- return this._createURL({
196
+ var url = this._createURL({
154
197
  qsModule: _qs.default,
155
198
  routeState: routeState,
156
199
  location: this.getLocation()
157
200
  });
201
+ if (process.env.NODE_ENV === 'development') {
202
+ try {
203
+ // We just want to check if the URL is valid.
204
+ // eslint-disable-next-line no-new
205
+ new URL(url);
206
+ } catch (e) {
207
+ process.env.NODE_ENV === 'development' ? (0, _utils.warning)(false, "The URL returned by the `createURL` function is invalid.\nPlease make sure it returns an absolute URL to avoid issues, e.g: `https://algolia.com/search?query=iphone`.") : void 0;
208
+ }
209
+ }
210
+ return url;
158
211
  }
159
212
 
160
213
  /**
@@ -26,13 +26,14 @@ function createInitArgs(instantSearchInstance, parent, uiState) {
26
26
  }
27
27
  function createRenderArgs(instantSearchInstance, parent) {
28
28
  var results = parent.getResults();
29
+ var helper = parent.getHelper();
29
30
  return {
30
- helper: parent.getHelper(),
31
+ helper: helper,
31
32
  parent: parent,
32
33
  instantSearchInstance: instantSearchInstance,
33
34
  results: results,
34
35
  scopedResults: parent.getScopedResults(),
35
- state: results._state,
36
+ state: results ? results._state : helper.state,
36
37
  renderState: instantSearchInstance.renderState,
37
38
  templatesConfig: instantSearchInstance.templatesConfig,
38
39
  createURL: parent.createURL,
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = '4.55.0';
7
+ var _default = '4.56.0';
8
8
  exports.default = _default;
@@ -38,7 +38,9 @@ var renderer = function renderer(_ref) {
38
38
  }, (0, _preact.h)(_Selector.default, {
39
39
  cssClasses: cssClasses,
40
40
  currentValue: currentValue,
41
- options: items,
41
+ options: items
42
+ // @ts-expect-error: the refine function expects a number, but setValue will call it with a string. We don't want to change the type of the refine function because it's part of the connector API.
43
+ ,
42
44
  setValue: refine
43
45
  })), containerNode);
44
46
  };
@@ -339,7 +339,7 @@ var index = function index(widgetParams) {
339
339
  // does not have access to lastResults, which it used to in pre-federated
340
340
  // search behavior.
341
341
  helper.lastResults = results;
342
- lastValidSearchParameters = results._state;
342
+ lastValidSearchParameters = results === null || results === void 0 ? void 0 : results._state;
343
343
  });
344
344
 
345
345
  // We compute the render state before calling `init` in a separate loop
@@ -395,16 +395,16 @@ var index = function index(widgetParams) {
395
395
  render: function render(_ref5) {
396
396
  var _this4 = this;
397
397
  var instantSearchInstance = _ref5.instantSearchInstance;
398
- if (!this.getResults()) {
399
- return;
400
- }
401
-
402
398
  // we can't attach a listener to the error event of search, as the error
403
399
  // then would no longer be thrown for global handlers.
404
- if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests()) {
400
+ if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests() && lastValidSearchParameters) {
405
401
  helper.setState(lastValidSearchParameters);
406
402
  }
407
- localWidgets.forEach(function (widget) {
403
+
404
+ // We only render index widgets if there are no results.
405
+ // This makes sure `render` is never called with `results` being `null`.
406
+ var widgetsToRender = this.getResults() ? localWidgets : localWidgets.filter(_utils.isIndexWidget);
407
+ widgetsToRender.forEach(function (widget) {
408
408
  if (widget.getRenderState) {
409
409
  var renderState = widget.getRenderState(instantSearchInstance.renderState[_this4.getIndexId()] || {}, (0, _utils.createRenderArgs)(instantSearchInstance, _this4));
410
410
  storeRenderState({
@@ -414,7 +414,7 @@ var index = function index(widgetParams) {
414
414
  });
415
415
  }
416
416
  });
417
- localWidgets.forEach(function (widget) {
417
+ widgetsToRender.forEach(function (widget) {
418
418
  // At this point, all the variables used below are set. Both `helper`
419
419
  // and `derivedHelper` have been created at the `init` step. The attribute
420
420
  // `lastResults` might be `null` though. It's possible that a stalled render