instantsearch.js 4.49.3 → 4.50.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.
@@ -44,7 +44,7 @@ function Pagination(props) {
44
44
  }), props.pages.map(function (pageNumber) {
45
45
  return (0, _preact.h)(PaginationLink, {
46
46
  key: pageNumber,
47
- ariaLabel: "".concat(pageNumber + 1),
47
+ ariaLabel: "Page ".concat(pageNumber + 1),
48
48
  className: props.cssClasses.pageItem,
49
49
  isSelected: pageNumber === props.currentPage,
50
50
  label: "".concat(pageNumber + 1),
@@ -61,7 +61,8 @@ var connectHits = function connectHits(renderFn) {
61
61
  if (!bindEvent) {
62
62
  bindEvent = (0, _utils.createBindEventForHits)({
63
63
  index: helper.getIndex(),
64
- widgetType: this.$$type
64
+ widgetType: this.$$type,
65
+ instantSearchInstance: instantSearchInstance
65
66
  });
66
67
  }
67
68
  if (!results) {
@@ -151,7 +151,8 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
151
151
  });
152
152
  bindEvent = (0, _utils.createBindEventForHits)({
153
153
  index: helper.getIndex(),
154
- widgetType: this.$$type
154
+ widgetType: this.$$type,
155
+ instantSearchInstance: instantSearchInstance
155
156
  });
156
157
  isFirstPage = state.page === undefined || getFirstReceivedPage(state, cachedHits) === 0;
157
158
  } else {
@@ -165,7 +166,7 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
165
166
  var transformedHits = transformItems(hitsWithAbsolutePositionAndQueryID, {
166
167
  results: results
167
168
  });
168
- if (cachedHits[_page] === undefined && !results.__isArtificial) {
169
+ if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle') {
169
170
  cachedHits[_page] = transformedHits;
170
171
  cache.write({
171
172
  state: state,
@@ -80,8 +80,9 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
80
80
  }
81
81
  }));
82
82
  _defineProperty(_assertThisInitialized(_this), "scheduleRender", (0, _utils.defer)(function () {
83
+ var _this$mainHelper;
83
84
  var shouldResetStatus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
84
- if (!_this.mainHelper.hasPendingRequests()) {
85
+ if (!((_this$mainHelper = _this.mainHelper) !== null && _this$mainHelper !== void 0 && _this$mainHelper.hasPendingRequests())) {
85
86
  clearTimeout(_this._searchStalledTimer);
86
87
  _this._searchStalledTimer = null;
87
88
  if (shouldResetStatus) {
@@ -349,12 +350,7 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
349
350
  var mainHelper = this.mainHelper || (0, _algoliasearchHelper.default)(this.client, this.indexName);
350
351
  mainHelper.search = function () {
351
352
  _this3.status = 'loading';
352
- // @MAJOR: use scheduleRender here
353
- // For now, widgets don't expect to be rendered at the start of `loading`,
354
- // so it would be a breaking change to add an extra render. We don't have
355
- // these guarantees about the render event, thus emitting it once more
356
- // isn't a breaking change.
357
- _this3.emit('render');
353
+ _this3.scheduleRender(false);
358
354
 
359
355
  // This solution allows us to keep the exact same API for the users but
360
356
  // under the hood, we have a different implementation. It should be
@@ -57,6 +57,9 @@ function renderTemplate(_ref) {
57
57
  Snippet: _components.Snippet,
58
58
  ReverseSnippet: _components.ReverseSnippet
59
59
  };
60
+
61
+ // @MAJOR remove the `as any` when string templates are removed
62
+ // needed because not every template receives sendEvent
60
63
  return template(data, params);
61
64
  }
62
65
  var transformedHelpers = transformHelpersToHogan(helpers, compileOptions, data);
@@ -20,7 +20,7 @@ var buildPayloads = function buildPayloads(_ref) {
20
20
  widgetType = _ref.widgetType,
21
21
  methodName = _ref.methodName,
22
22
  args = _ref.args,
23
- isSearchStalled = _ref.isSearchStalled;
23
+ instantSearchInstance = _ref.instantSearchInstance;
24
24
  // when there's only one argument, that means it's custom
25
25
  if (args.length === 1 && _typeof(args[0]) === 'object') {
26
26
  return [args[0]];
@@ -59,7 +59,7 @@ var buildPayloads = function buildPayloads(_ref) {
59
59
  });
60
60
  });
61
61
  if (eventType === 'view') {
62
- if (isSearchStalled) {
62
+ if (instantSearchInstance.status !== 'idle') {
63
63
  return [];
64
64
  }
65
65
  return hitsChunks.map(function (batch, i) {
@@ -129,7 +129,7 @@ function createSendEventForHits(_ref2) {
129
129
  index: index,
130
130
  methodName: 'sendEvent',
131
131
  args: args,
132
- isSearchStalled: instantSearchInstance.status === 'stalled'
132
+ instantSearchInstance: instantSearchInstance
133
133
  });
134
134
  payloads.forEach(function (payload) {
135
135
  return instantSearchInstance.sendEventToInsights(payload);
@@ -139,7 +139,8 @@ function createSendEventForHits(_ref2) {
139
139
  }
140
140
  function createBindEventForHits(_ref3) {
141
141
  var index = _ref3.index,
142
- widgetType = _ref3.widgetType;
142
+ widgetType = _ref3.widgetType,
143
+ instantSearchInstance = _ref3.instantSearchInstance;
143
144
  var bindEventForHits = function bindEventForHits() {
144
145
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
145
146
  args[_key2] = arguments[_key2];
@@ -149,7 +150,7 @@ function createBindEventForHits(_ref3) {
149
150
  index: index,
150
151
  methodName: 'bindEvent',
151
152
  args: args,
152
- isSearchStalled: false
153
+ instantSearchInstance: instantSearchInstance
153
154
  });
154
155
  return payloads.length ? "data-insights-event=".concat((0, _serializer.serializePayload)(payloads)) : '';
155
156
  };
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = '4.49.3';
7
+ var _default = '4.50.0';
8
8
  exports.default = _default;
@@ -108,6 +108,7 @@ var index = function index(widgetParams) {
108
108
  var localParent = null;
109
109
  var helper = null;
110
110
  var derivedHelper = null;
111
+ var lastValidSearchParameters = null;
111
112
  return {
112
113
  $$type: 'ais.index',
113
114
  $$widgetType: 'ais.index',
@@ -121,7 +122,16 @@ var index = function index(widgetParams) {
121
122
  return helper;
122
123
  },
123
124
  getResults: function getResults() {
124
- return derivedHelper && derivedHelper.lastResults;
125
+ var _derivedHelper;
126
+ if (!((_derivedHelper = derivedHelper) !== null && _derivedHelper !== void 0 && _derivedHelper.lastResults)) return null;
127
+
128
+ // To make the UI optimistic, we patch the state to display to the current
129
+ // one instead of the one associated with the latest results.
130
+ // This means user-driven UI changes (e.g., checked checkbox) are reflected
131
+ // immediately instead of waiting for Algolia to respond, regardless of
132
+ // the status of the network request.
133
+ derivedHelper.lastResults._state = helper.state;
134
+ return derivedHelper.lastResults;
125
135
  },
126
136
  getScopedResults: function getScopedResults() {
127
137
  var widgetParent = this.getParent();
@@ -326,6 +336,7 @@ var index = function index(widgetParams) {
326
336
  // does not have access to lastResults, which it used to in pre-federated
327
337
  // search behavior.
328
338
  helper.lastResults = results;
339
+ lastValidSearchParameters = results._state;
329
340
  });
330
341
 
331
342
  // We compute the render state before calling `init` in a separate loop
@@ -384,6 +395,12 @@ var index = function index(widgetParams) {
384
395
  if (!this.getResults()) {
385
396
  return;
386
397
  }
398
+
399
+ // we can't attach a listener to the error event of search, as the error
400
+ // then would no longer be thrown for global handlers.
401
+ if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests()) {
402
+ helper.setState(lastValidSearchParameters);
403
+ }
387
404
  localWidgets.forEach(function (widget) {
388
405
  if (widget.getRenderState) {
389
406
  var renderState = widget.getRenderState(instantSearchInstance.renderState[_this4.getIndexId()] || {}, (0, _utils.createRenderArgs)(instantSearchInstance, _this4));
@@ -5052,7 +5052,7 @@ declare type Status = 'initial' | 'askingPermission' | 'waiting' | 'recognizing'
5052
5052
 
5053
5053
  declare type Template<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string);
5054
5054
 
5055
- declare type TemplateParams = BindEventForHits & {
5055
+ declare type TemplateParams = {
5056
5056
  html: typeof html;
5057
5057
  components: {
5058
5058
  Highlight: typeof Highlight;
@@ -5067,7 +5067,15 @@ declare type Templates = {
5067
5067
  [key: string]: Template<any> | TemplateWithBindEvent<any> | undefined;
5068
5068
  };
5069
5069
 
5070
- declare type TemplateWithBindEvent<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string);
5070
+ declare type TemplateWithBindEvent<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateWithBindEventParams) => VNode | VNode[] | string);
5071
+
5072
+ declare interface TemplateWithBindEventParams extends TemplateParams {
5073
+ /** @deprecated use sendEvent instead */
5074
+ (...args: Parameters<BuiltInBindEventForHits>): ReturnType<BuiltInBindEventForHits>;
5075
+ /** @deprecated use sendEvent instead */
5076
+ (...args: Parameters<CustomBindEventForHits>): ReturnType<CustomBindEventForHits>;
5077
+ sendEvent: SendEventForHits;
5078
+ }
5071
5079
 
5072
5080
  declare type TextTemplateProps = {
5073
5081
  hasManyResults: boolean;
@@ -1,4 +1,4 @@
1
- /*! InstantSearch.js 4.49.3 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch.js */
1
+ /*! InstantSearch.js 4.50.0 | © Algolia, Inc. and contributors; MIT License | https://github.com/algolia/instantsearch.js */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
4
4
  typeof define === 'function' && define.amd ? define(factory) :
@@ -333,7 +333,8 @@
333
333
  for (var key in source) {
334
334
  if (
335
335
  !Object.prototype.hasOwnProperty.call(source, key) ||
336
- key === '__proto__'
336
+ key === '__proto__' ||
337
+ key === 'constructor'
337
338
  ) {
338
339
  continue;
339
340
  }
@@ -3149,7 +3150,33 @@
3149
3150
  };
3150
3151
  });
3151
3152
  } else if (results._state.isHierarchicalFacet(attribute)) {
3152
- return find(results.hierarchicalFacets, predicate);
3153
+ var hierarchicalFacetValues = find(results.hierarchicalFacets, predicate);
3154
+ if (!hierarchicalFacetValues) return hierarchicalFacetValues;
3155
+
3156
+ var hierarchicalFacet = results._state.getHierarchicalFacetByName(attribute);
3157
+ var currentRefinementSplit = unescapeFacetValue$2(
3158
+ results._state.getHierarchicalRefinement(attribute)[0] || ''
3159
+ ).split(results._state._getHierarchicalFacetSeparator(hierarchicalFacet));
3160
+ currentRefinementSplit.unshift(attribute);
3161
+
3162
+ setIsRefined(hierarchicalFacetValues, currentRefinementSplit, 0);
3163
+
3164
+ return hierarchicalFacetValues;
3165
+ }
3166
+ }
3167
+
3168
+ /**
3169
+ * Set the isRefined of a hierarchical facet result based on the current state.
3170
+ * @param {SearchResults.HierarchicalFacet} item Hierarchical facet to fix
3171
+ * @param {string[]} currentRefinementSplit array of parts of the current hierarchical refinement
3172
+ * @param {number} depth recursion depth in the currentRefinement
3173
+ */
3174
+ function setIsRefined(item, currentRefinement, depth) {
3175
+ item.isRefined = item.name === currentRefinement[depth];
3176
+ if (item.data) {
3177
+ item.data.forEach(function(child) {
3178
+ setIsRefined(child, currentRefinement, depth + 1);
3179
+ });
3153
3180
  }
3154
3181
  }
3155
3182
 
@@ -4238,7 +4265,7 @@
4238
4265
 
4239
4266
  var requestBuilder_1 = requestBuilder;
4240
4267
 
4241
- var version = '3.11.1';
4268
+ var version = '3.11.3';
4242
4269
 
4243
4270
  var escapeFacetValue$3 = escapeFacetValue_1.escapeFacetValue;
4244
4271
 
@@ -4488,8 +4515,10 @@
4488
4515
  * @param {number} options.nbHits - Maximum number of answers to retrieve from the Answers Engine. Cannot be greater than 1000.
4489
4516
  *
4490
4517
  * @return {promise} the answer results
4518
+ * @deprecated answers is deprecated and will be replaced with new initiatives
4491
4519
  */
4492
4520
  AlgoliaSearchHelper.prototype.findAnswers = function(options) {
4521
+ console.warn('[algoliasearch-helper] answers is no longer supported');
4493
4522
  var state = this.state;
4494
4523
  var derivedHelper = this.derivedHelpers[0];
4495
4524
  if (!derivedHelper) {
@@ -6275,7 +6304,7 @@
6275
6304
  widgetType = _ref.widgetType,
6276
6305
  methodName = _ref.methodName,
6277
6306
  args = _ref.args,
6278
- isSearchStalled = _ref.isSearchStalled;
6307
+ instantSearchInstance = _ref.instantSearchInstance;
6279
6308
  // when there's only one argument, that means it's custom
6280
6309
  if (args.length === 1 && _typeof(args[0]) === 'object') {
6281
6310
  return [args[0]];
@@ -6310,7 +6339,7 @@
6310
6339
  });
6311
6340
  });
6312
6341
  if (eventType === 'view') {
6313
- if (isSearchStalled) {
6342
+ if (instantSearchInstance.status !== 'idle') {
6314
6343
  return [];
6315
6344
  }
6316
6345
  return hitsChunks.map(function (batch, i) {
@@ -6378,7 +6407,7 @@
6378
6407
  index: index,
6379
6408
  methodName: 'sendEvent',
6380
6409
  args: args,
6381
- isSearchStalled: instantSearchInstance.status === 'stalled'
6410
+ instantSearchInstance: instantSearchInstance
6382
6411
  });
6383
6412
  payloads.forEach(function (payload) {
6384
6413
  return instantSearchInstance.sendEventToInsights(payload);
@@ -6388,7 +6417,8 @@
6388
6417
  }
6389
6418
  function createBindEventForHits(_ref3) {
6390
6419
  var index = _ref3.index,
6391
- widgetType = _ref3.widgetType;
6420
+ widgetType = _ref3.widgetType,
6421
+ instantSearchInstance = _ref3.instantSearchInstance;
6392
6422
  var bindEventForHits = function bindEventForHits() {
6393
6423
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
6394
6424
  args[_key2] = arguments[_key2];
@@ -6398,7 +6428,7 @@
6398
6428
  index: index,
6399
6429
  methodName: 'bindEvent',
6400
6430
  args: args,
6401
- isSearchStalled: false
6431
+ instantSearchInstance: instantSearchInstance
6402
6432
  });
6403
6433
  return payloads.length ? "data-insights-event=".concat(serializePayload(payloads)) : '';
6404
6434
  };
@@ -7215,6 +7245,7 @@
7215
7245
  var localParent = null;
7216
7246
  var helper = null;
7217
7247
  var derivedHelper = null;
7248
+ var lastValidSearchParameters = null;
7218
7249
  return {
7219
7250
  $$type: 'ais.index',
7220
7251
  $$widgetType: 'ais.index',
@@ -7228,7 +7259,16 @@
7228
7259
  return helper;
7229
7260
  },
7230
7261
  getResults: function getResults() {
7231
- return derivedHelper && derivedHelper.lastResults;
7262
+ var _derivedHelper;
7263
+ if (!((_derivedHelper = derivedHelper) !== null && _derivedHelper !== void 0 && _derivedHelper.lastResults)) return null;
7264
+
7265
+ // To make the UI optimistic, we patch the state to display to the current
7266
+ // one instead of the one associated with the latest results.
7267
+ // This means user-driven UI changes (e.g., checked checkbox) are reflected
7268
+ // immediately instead of waiting for Algolia to respond, regardless of
7269
+ // the status of the network request.
7270
+ derivedHelper.lastResults._state = helper.state;
7271
+ return derivedHelper.lastResults;
7232
7272
  },
7233
7273
  getScopedResults: function getScopedResults() {
7234
7274
  var widgetParent = this.getParent();
@@ -7433,6 +7473,7 @@
7433
7473
  // does not have access to lastResults, which it used to in pre-federated
7434
7474
  // search behavior.
7435
7475
  helper.lastResults = results;
7476
+ lastValidSearchParameters = results._state;
7436
7477
  });
7437
7478
 
7438
7479
  // We compute the render state before calling `init` in a separate loop
@@ -7491,6 +7532,12 @@
7491
7532
  if (!this.getResults()) {
7492
7533
  return;
7493
7534
  }
7535
+
7536
+ // we can't attach a listener to the error event of search, as the error
7537
+ // then would no longer be thrown for global handlers.
7538
+ if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests()) {
7539
+ helper.setState(lastValidSearchParameters);
7540
+ }
7494
7541
  localWidgets.forEach(function (widget) {
7495
7542
  if (widget.getRenderState) {
7496
7543
  var renderState = widget.getRenderState(instantSearchInstance.renderState[_this4.getIndexId()] || {}, createRenderArgs(instantSearchInstance, _this4));
@@ -7570,7 +7617,7 @@
7570
7617
  instantSearchInstance.renderState = _objectSpread2(_objectSpread2({}, instantSearchInstance.renderState), {}, _defineProperty({}, parentIndexName, _objectSpread2(_objectSpread2({}, instantSearchInstance.renderState[parentIndexName]), renderState)));
7571
7618
  }
7572
7619
 
7573
- var version$1 = '4.49.3';
7620
+ var version$1 = '4.50.0';
7574
7621
 
7575
7622
  var NAMESPACE = 'ais';
7576
7623
  var component = function component(componentName) {
@@ -9042,8 +9089,9 @@
9042
9089
  }
9043
9090
  }));
9044
9091
  _defineProperty(_assertThisInitialized(_this), "scheduleRender", defer(function () {
9092
+ var _this$mainHelper;
9045
9093
  var shouldResetStatus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
9046
- if (!_this.mainHelper.hasPendingRequests()) {
9094
+ if (!((_this$mainHelper = _this.mainHelper) !== null && _this$mainHelper !== void 0 && _this$mainHelper.hasPendingRequests())) {
9047
9095
  clearTimeout(_this._searchStalledTimer);
9048
9096
  _this._searchStalledTimer = null;
9049
9097
  if (shouldResetStatus) {
@@ -9311,12 +9359,7 @@
9311
9359
  var mainHelper = this.mainHelper || algoliasearchHelper_1(this.client, this.indexName);
9312
9360
  mainHelper.search = function () {
9313
9361
  _this3.status = 'loading';
9314
- // @MAJOR: use scheduleRender here
9315
- // For now, widgets don't expect to be rendered at the start of `loading`,
9316
- // so it would be a breaking change to add an extra render. We don't have
9317
- // these guarantees about the render event, thus emitting it once more
9318
- // isn't a breaking change.
9319
- _this3.emit('render');
9362
+ _this3.scheduleRender(false);
9320
9363
 
9321
9364
  // This solution allows us to keep the exact same API for the users but
9322
9365
  // under the hood, we have a different implementation. It should be
@@ -10112,7 +10155,8 @@
10112
10155
  if (!bindEvent) {
10113
10156
  bindEvent = createBindEventForHits({
10114
10157
  index: helper.getIndex(),
10115
- widgetType: this.$$type
10158
+ widgetType: this.$$type,
10159
+ instantSearchInstance: instantSearchInstance
10116
10160
  });
10117
10161
  }
10118
10162
  if (!results) {
@@ -10584,7 +10628,8 @@
10584
10628
  });
10585
10629
  bindEvent = createBindEventForHits({
10586
10630
  index: helper.getIndex(),
10587
- widgetType: this.$$type
10631
+ widgetType: this.$$type,
10632
+ instantSearchInstance: instantSearchInstance
10588
10633
  });
10589
10634
  isFirstPage = state.page === undefined || getFirstReceivedPage(state, cachedHits) === 0;
10590
10635
  } else {
@@ -10598,7 +10643,7 @@
10598
10643
  var transformedHits = transformItems(hitsWithAbsolutePositionAndQueryID, {
10599
10644
  results: results
10600
10645
  });
10601
- if (cachedHits[_page] === undefined && !results.__isArtificial) {
10646
+ if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle') {
10602
10647
  cachedHits[_page] = transformedHits;
10603
10648
  cache.write({
10604
10649
  state: state,
@@ -15276,6 +15321,9 @@
15276
15321
  Snippet: Snippet$1,
15277
15322
  ReverseSnippet: ReverseSnippet$1
15278
15323
  };
15324
+
15325
+ // @MAJOR remove the `as any` when string templates are removed
15326
+ // needed because not every template receives sendEvent
15279
15327
  return template(data, params);
15280
15328
  }
15281
15329
  var transformedHelpers = transformHelpersToHogan(helpers, compileOptions, data);
@@ -17899,7 +17947,7 @@
17899
17947
  }), props.pages.map(function (pageNumber) {
17900
17948
  return h(PaginationLink, {
17901
17949
  key: pageNumber,
17902
- ariaLabel: "".concat(pageNumber + 1),
17950
+ ariaLabel: "Page ".concat(pageNumber + 1),
17903
17951
  className: props.cssClasses.pageItem,
17904
17952
  isSelected: pageNumber === props.currentPage,
17905
17953
  label: "".concat(pageNumber + 1),