instantsearch.js 4.49.4 → 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.4';
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.4 | © 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) :
@@ -3150,7 +3150,33 @@
3150
3150
  };
3151
3151
  });
3152
3152
  } else if (results._state.isHierarchicalFacet(attribute)) {
3153
- 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
+ });
3154
3180
  }
3155
3181
  }
3156
3182
 
@@ -4239,7 +4265,7 @@
4239
4265
 
4240
4266
  var requestBuilder_1 = requestBuilder;
4241
4267
 
4242
- var version = '3.11.2';
4268
+ var version = '3.11.3';
4243
4269
 
4244
4270
  var escapeFacetValue$3 = escapeFacetValue_1.escapeFacetValue;
4245
4271
 
@@ -6278,7 +6304,7 @@
6278
6304
  widgetType = _ref.widgetType,
6279
6305
  methodName = _ref.methodName,
6280
6306
  args = _ref.args,
6281
- isSearchStalled = _ref.isSearchStalled;
6307
+ instantSearchInstance = _ref.instantSearchInstance;
6282
6308
  // when there's only one argument, that means it's custom
6283
6309
  if (args.length === 1 && _typeof(args[0]) === 'object') {
6284
6310
  return [args[0]];
@@ -6313,7 +6339,7 @@
6313
6339
  });
6314
6340
  });
6315
6341
  if (eventType === 'view') {
6316
- if (isSearchStalled) {
6342
+ if (instantSearchInstance.status !== 'idle') {
6317
6343
  return [];
6318
6344
  }
6319
6345
  return hitsChunks.map(function (batch, i) {
@@ -6381,7 +6407,7 @@
6381
6407
  index: index,
6382
6408
  methodName: 'sendEvent',
6383
6409
  args: args,
6384
- isSearchStalled: instantSearchInstance.status === 'stalled'
6410
+ instantSearchInstance: instantSearchInstance
6385
6411
  });
6386
6412
  payloads.forEach(function (payload) {
6387
6413
  return instantSearchInstance.sendEventToInsights(payload);
@@ -6391,7 +6417,8 @@
6391
6417
  }
6392
6418
  function createBindEventForHits(_ref3) {
6393
6419
  var index = _ref3.index,
6394
- widgetType = _ref3.widgetType;
6420
+ widgetType = _ref3.widgetType,
6421
+ instantSearchInstance = _ref3.instantSearchInstance;
6395
6422
  var bindEventForHits = function bindEventForHits() {
6396
6423
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
6397
6424
  args[_key2] = arguments[_key2];
@@ -6401,7 +6428,7 @@
6401
6428
  index: index,
6402
6429
  methodName: 'bindEvent',
6403
6430
  args: args,
6404
- isSearchStalled: false
6431
+ instantSearchInstance: instantSearchInstance
6405
6432
  });
6406
6433
  return payloads.length ? "data-insights-event=".concat(serializePayload(payloads)) : '';
6407
6434
  };
@@ -7218,6 +7245,7 @@
7218
7245
  var localParent = null;
7219
7246
  var helper = null;
7220
7247
  var derivedHelper = null;
7248
+ var lastValidSearchParameters = null;
7221
7249
  return {
7222
7250
  $$type: 'ais.index',
7223
7251
  $$widgetType: 'ais.index',
@@ -7231,7 +7259,16 @@
7231
7259
  return helper;
7232
7260
  },
7233
7261
  getResults: function getResults() {
7234
- 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;
7235
7272
  },
7236
7273
  getScopedResults: function getScopedResults() {
7237
7274
  var widgetParent = this.getParent();
@@ -7436,6 +7473,7 @@
7436
7473
  // does not have access to lastResults, which it used to in pre-federated
7437
7474
  // search behavior.
7438
7475
  helper.lastResults = results;
7476
+ lastValidSearchParameters = results._state;
7439
7477
  });
7440
7478
 
7441
7479
  // We compute the render state before calling `init` in a separate loop
@@ -7494,6 +7532,12 @@
7494
7532
  if (!this.getResults()) {
7495
7533
  return;
7496
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
+ }
7497
7541
  localWidgets.forEach(function (widget) {
7498
7542
  if (widget.getRenderState) {
7499
7543
  var renderState = widget.getRenderState(instantSearchInstance.renderState[_this4.getIndexId()] || {}, createRenderArgs(instantSearchInstance, _this4));
@@ -7573,7 +7617,7 @@
7573
7617
  instantSearchInstance.renderState = _objectSpread2(_objectSpread2({}, instantSearchInstance.renderState), {}, _defineProperty({}, parentIndexName, _objectSpread2(_objectSpread2({}, instantSearchInstance.renderState[parentIndexName]), renderState)));
7574
7618
  }
7575
7619
 
7576
- var version$1 = '4.49.4';
7620
+ var version$1 = '4.50.0';
7577
7621
 
7578
7622
  var NAMESPACE = 'ais';
7579
7623
  var component = function component(componentName) {
@@ -9045,8 +9089,9 @@
9045
9089
  }
9046
9090
  }));
9047
9091
  _defineProperty(_assertThisInitialized(_this), "scheduleRender", defer(function () {
9092
+ var _this$mainHelper;
9048
9093
  var shouldResetStatus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
9049
- if (!_this.mainHelper.hasPendingRequests()) {
9094
+ if (!((_this$mainHelper = _this.mainHelper) !== null && _this$mainHelper !== void 0 && _this$mainHelper.hasPendingRequests())) {
9050
9095
  clearTimeout(_this._searchStalledTimer);
9051
9096
  _this._searchStalledTimer = null;
9052
9097
  if (shouldResetStatus) {
@@ -9314,12 +9359,7 @@
9314
9359
  var mainHelper = this.mainHelper || algoliasearchHelper_1(this.client, this.indexName);
9315
9360
  mainHelper.search = function () {
9316
9361
  _this3.status = 'loading';
9317
- // @MAJOR: use scheduleRender here
9318
- // For now, widgets don't expect to be rendered at the start of `loading`,
9319
- // so it would be a breaking change to add an extra render. We don't have
9320
- // these guarantees about the render event, thus emitting it once more
9321
- // isn't a breaking change.
9322
- _this3.emit('render');
9362
+ _this3.scheduleRender(false);
9323
9363
 
9324
9364
  // This solution allows us to keep the exact same API for the users but
9325
9365
  // under the hood, we have a different implementation. It should be
@@ -10115,7 +10155,8 @@
10115
10155
  if (!bindEvent) {
10116
10156
  bindEvent = createBindEventForHits({
10117
10157
  index: helper.getIndex(),
10118
- widgetType: this.$$type
10158
+ widgetType: this.$$type,
10159
+ instantSearchInstance: instantSearchInstance
10119
10160
  });
10120
10161
  }
10121
10162
  if (!results) {
@@ -10587,7 +10628,8 @@
10587
10628
  });
10588
10629
  bindEvent = createBindEventForHits({
10589
10630
  index: helper.getIndex(),
10590
- widgetType: this.$$type
10631
+ widgetType: this.$$type,
10632
+ instantSearchInstance: instantSearchInstance
10591
10633
  });
10592
10634
  isFirstPage = state.page === undefined || getFirstReceivedPage(state, cachedHits) === 0;
10593
10635
  } else {
@@ -10601,7 +10643,7 @@
10601
10643
  var transformedHits = transformItems(hitsWithAbsolutePositionAndQueryID, {
10602
10644
  results: results
10603
10645
  });
10604
- if (cachedHits[_page] === undefined && !results.__isArtificial) {
10646
+ if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle') {
10605
10647
  cachedHits[_page] = transformedHits;
10606
10648
  cache.write({
10607
10649
  state: state,
@@ -15279,6 +15321,9 @@
15279
15321
  Snippet: Snippet$1,
15280
15322
  ReverseSnippet: ReverseSnippet$1
15281
15323
  };
15324
+
15325
+ // @MAJOR remove the `as any` when string templates are removed
15326
+ // needed because not every template receives sendEvent
15282
15327
  return template(data, params);
15283
15328
  }
15284
15329
  var transformedHelpers = transformHelpersToHogan(helpers, compileOptions, data);
@@ -17902,7 +17947,7 @@
17902
17947
  }), props.pages.map(function (pageNumber) {
17903
17948
  return h(PaginationLink, {
17904
17949
  key: pageNumber,
17905
- ariaLabel: "".concat(pageNumber + 1),
17950
+ ariaLabel: "Page ".concat(pageNumber + 1),
17906
17951
  className: props.cssClasses.pageItem,
17907
17952
  isSelected: pageNumber === props.currentPage,
17908
17953
  label: "".concat(pageNumber + 1),