instantsearch.js 4.79.1 → 4.80.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.
@@ -66,7 +66,7 @@ var RawHtml = /*#__PURE__*/function (_Component) {
66
66
  });
67
67
  // if there is one TextNode first and one TextNode last, the
68
68
  // last one's nodeValue will be assigned to the first.
69
- if (this.nodes[0].nodeValue) {
69
+ if (this.nodes[0] && this.nodes[0].nodeValue) {
70
70
  this.nodes[0].nodeValue = '';
71
71
  }
72
72
  }
@@ -98,22 +98,20 @@ var connectInfiniteHits = exports.default = function connectInfiniteHits(renderF
98
98
  return Math.max.apply(Math, [page].concat(_toConsumableArray(pages)));
99
99
  }
100
100
  };
101
- var getShowPrevious = function getShowPrevious(helper) {
101
+ var getShowPrevious = function getShowPrevious(helper, getCachedHits) {
102
102
  return function () {
103
+ var cachedHits = getCachedHits();
103
104
  // Using the helper's `overrideStateWithoutTriggeringChangeEvent` method
104
105
  // avoid updating the browser URL when the user displays the previous page.
105
106
  helper.overrideStateWithoutTriggeringChangeEvent(_objectSpread(_objectSpread({}, helper.state), {}, {
106
- page: getFirstReceivedPage(helper.state, cache.read({
107
- state: normalizeState(helper.state)
108
- }) || {}) - 1
107
+ page: getFirstReceivedPage(helper.state, cachedHits) - 1
109
108
  })).searchWithoutTriggeringOnStateChange();
110
109
  };
111
110
  };
112
- var getShowMore = function getShowMore(helper) {
111
+ var getShowMore = function getShowMore(helper, getCachedHits) {
113
112
  return function () {
114
- helper.setPage(getLastReceivedPage(helper.state, cache.read({
115
- state: normalizeState(helper.state)
116
- }) || {}) + 1).search();
113
+ var cachedHits = getCachedHits();
114
+ helper.setPage(getLastReceivedPage(helper.state, cachedHits) + 1).search();
117
115
  };
118
116
  };
119
117
  return {
@@ -145,6 +143,12 @@ var connectInfiniteHits = exports.default = function connectInfiniteHits(renderF
145
143
  parent = _ref6.parent,
146
144
  existingState = _ref6.state,
147
145
  instantSearchInstance = _ref6.instantSearchInstance;
146
+ var getCacheHits = function getCacheHits() {
147
+ var state = parent.getPreviousState() || existingState;
148
+ return cache.read({
149
+ state: normalizeState(state)
150
+ }) || {};
151
+ };
148
152
  var isFirstPage;
149
153
  var currentPageHits = [];
150
154
  /**
@@ -153,13 +157,15 @@ var connectInfiniteHits = exports.default = function connectInfiniteHits(renderF
153
157
  * is loading.
154
158
  */
155
159
  var state = parent.getPreviousState() || existingState;
156
- var cachedHits = cache.read({
157
- state: normalizeState(state)
158
- }) || {};
160
+ var cachedHits = getCacheHits();
159
161
  var banner = results === null || results === void 0 ? void 0 : (_results$renderingCon = results.renderingContent) === null || _results$renderingCon === void 0 ? void 0 : (_results$renderingCon2 = _results$renderingCon.widgets) === null || _results$renderingCon2 === void 0 ? void 0 : (_results$renderingCon3 = _results$renderingCon2.banners) === null || _results$renderingCon3 === void 0 ? void 0 : _results$renderingCon3[0];
160
162
  if (!showPrevious) {
161
- showPrevious = getShowPrevious(helper);
162
- showMore = getShowMore(helper);
163
+ showPrevious = function showPrevious() {
164
+ return getShowPrevious(helper, getCacheHits)();
165
+ };
166
+ showMore = function showMore() {
167
+ return getShowMore(helper, getCacheHits)();
168
+ };
163
169
  }
164
170
  if (!sendEvent) {
165
171
  sendEvent = (0, _utils.createSendEventForHits)({
@@ -329,12 +329,9 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
329
329
  if (!Array.isArray(widgets)) {
330
330
  throw new Error(withUsage('The `addWidgets` method expects an array of widgets. Please use `addWidget`.'));
331
331
  }
332
- if (widgets.some(function (widget) {
333
- return typeof widget.init !== 'function' && typeof widget.render !== 'function';
332
+ if (this.compositionID && widgets.some(function (w) {
333
+ return !Array.isArray(w) && (0, _utils.isIndexWidget)(w) && !w._isolated;
334
334
  })) {
335
- throw new Error(withUsage('The widget definition expects a `render` and/or an `init` method.'));
336
- }
337
- if (this.compositionID && widgets.some(_utils.isIndexWidget)) {
338
335
  throw new Error(withUsage('The `index` widget cannot be used with a composition-based InstantSearch implementation.'));
339
336
  }
340
337
  this.mainIndex.addWidgets(widgets);
@@ -367,11 +364,6 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
367
364
  if (!Array.isArray(widgets)) {
368
365
  throw new Error(withUsage('The `removeWidgets` method expects an array of widgets. Please use `removeWidget`.'));
369
366
  }
370
- if (widgets.some(function (widget) {
371
- return typeof widget.dispose !== 'function';
372
- })) {
373
- throw new Error(withUsage('The widget definition expects a `dispose` method.'));
374
- }
375
367
  this.mainIndex.removeWidgets(widgets);
376
368
  return this;
377
369
  }
@@ -4,4 +4,4 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.default = void 0;
7
- var _default = exports.default = '4.79.1';
7
+ var _default = exports.default = '4.80.0';
@@ -117,12 +117,18 @@ function resolveScopedResultsFromWidgets(widgets) {
117
117
  }, []);
118
118
  }
119
119
  var index = function index(widgetParams) {
120
- if (widgetParams === undefined || widgetParams.indexName === undefined) {
120
+ if (widgetParams === undefined || widgetParams.indexName === undefined && !widgetParams.EXPERIMENTAL_isolated) {
121
121
  throw new Error(withUsage('The `indexName` option is required.'));
122
122
  }
123
- var indexName = widgetParams.indexName,
123
+
124
+ // When isolated=true, we use an empty string as the default indexName.
125
+ // This is intentional: isolated indices do not require a real index name.
126
+ var _widgetParams$indexNa = widgetParams.indexName,
127
+ indexName = _widgetParams$indexNa === void 0 ? '' : _widgetParams$indexNa,
124
128
  _widgetParams$indexId = widgetParams.indexId,
125
- indexId = _widgetParams$indexId === void 0 ? indexName : _widgetParams$indexId;
129
+ indexId = _widgetParams$indexId === void 0 ? indexName : _widgetParams$indexId,
130
+ _widgetParams$EXPERIM = widgetParams.EXPERIMENTAL_isolated,
131
+ isolated = _widgetParams$EXPERIM === void 0 ? false : _widgetParams$EXPERIM;
126
132
  var localWidgets = [];
127
133
  var localUiState = {};
128
134
  var localInstantSearchInstance = null;
@@ -135,6 +141,7 @@ var index = function index(widgetParams) {
135
141
  return {
136
142
  $$type: 'ais.index',
137
143
  $$widgetType: 'ais.index',
144
+ _isolated: isolated,
138
145
  getIndexName: function getIndexName() {
139
146
  return indexName;
140
147
  },
@@ -186,7 +193,7 @@ var index = function index(widgetParams) {
186
193
  return resolveScopedResultsFromWidgets(widgetSiblings);
187
194
  },
188
195
  getParent: function getParent() {
189
- return localParent;
196
+ return isolated ? null : localParent;
190
197
  },
191
198
  createURL: function createURL(nextState) {
192
199
  if (typeof nextState === 'function') {
@@ -205,12 +212,15 @@ var index = function index(widgetParams) {
205
212
  if (!Array.isArray(widgets)) {
206
213
  throw new Error(withUsage('The `addWidgets` method expects an array of widgets.'));
207
214
  }
208
- if (widgets.some(function (widget) {
215
+ var flatWidgets = widgets.reduce(function (acc, w) {
216
+ return acc.concat(Array.isArray(w) ? w : [w]);
217
+ }, []);
218
+ if (flatWidgets.some(function (widget) {
209
219
  return typeof widget.init !== 'function' && typeof widget.render !== 'function';
210
220
  })) {
211
221
  throw new Error(withUsage('The widget definition expects a `render` and/or an `init` method.'));
212
222
  }
213
- widgets.forEach(function (widget) {
223
+ flatWidgets.forEach(function (widget) {
214
224
  if ((0, _utils.isIndexWidget)(widget)) {
215
225
  return;
216
226
  }
@@ -225,8 +235,8 @@ var index = function index(widgetParams) {
225
235
  }
226
236
  (0, _addWidgetId.addWidgetId)(widget);
227
237
  });
228
- localWidgets = localWidgets.concat(widgets);
229
- if (localInstantSearchInstance && Boolean(widgets.length)) {
238
+ localWidgets = localWidgets.concat(flatWidgets);
239
+ if (localInstantSearchInstance && Boolean(flatWidgets.length)) {
230
240
  privateHelperSetState(helper, {
231
241
  state: getLocalWidgetsSearchParameters(localWidgets, {
232
242
  uiState: localUiState,
@@ -242,7 +252,7 @@ var index = function index(widgetParams) {
242
252
  // We compute the render state before calling `init` in a separate loop
243
253
  // to construct the whole render state object that is then passed to
244
254
  // `init`.
245
- widgets.forEach(function (widget) {
255
+ flatWidgets.forEach(function (widget) {
246
256
  if (widget.getRenderState) {
247
257
  var renderState = widget.getRenderState(localInstantSearchInstance.renderState[_this.getIndexId()] || {}, (0, _utils.createInitArgs)(localInstantSearchInstance, _this, localInstantSearchInstance._initialUiState));
248
258
  storeRenderState({
@@ -252,12 +262,17 @@ var index = function index(widgetParams) {
252
262
  });
253
263
  }
254
264
  });
255
- widgets.forEach(function (widget) {
265
+ flatWidgets.forEach(function (widget) {
256
266
  if (widget.init) {
257
267
  widget.init((0, _utils.createInitArgs)(localInstantSearchInstance, _this, localInstantSearchInstance._initialUiState));
258
268
  }
259
269
  });
260
- localInstantSearchInstance.scheduleSearch();
270
+ if (isolated) {
271
+ var _helper2;
272
+ (_helper2 = helper) === null || _helper2 === void 0 ? void 0 : _helper2.search();
273
+ } else {
274
+ localInstantSearchInstance.scheduleSearch();
275
+ }
261
276
  }
262
277
  return this;
263
278
  },
@@ -266,13 +281,16 @@ var index = function index(widgetParams) {
266
281
  if (!Array.isArray(widgets)) {
267
282
  throw new Error(withUsage('The `removeWidgets` method expects an array of widgets.'));
268
283
  }
269
- if (widgets.some(function (widget) {
284
+ var flatWidgets = widgets.reduce(function (acc, w) {
285
+ return acc.concat(Array.isArray(w) ? w : [w]);
286
+ }, []);
287
+ if (flatWidgets.some(function (widget) {
270
288
  return typeof widget.dispose !== 'function';
271
289
  })) {
272
290
  throw new Error(withUsage('The widget definition expects a `dispose` method.'));
273
291
  }
274
292
  localWidgets = localWidgets.filter(function (widget) {
275
- return widgets.indexOf(widget) === -1;
293
+ return flatWidgets.indexOf(widget) === -1;
276
294
  });
277
295
  localWidgets.forEach(function (widget) {
278
296
  if ((0, _utils.isIndexWidget)(widget)) {
@@ -288,8 +306,8 @@ var index = function index(widgetParams) {
288
306
  hasSearchWidget = true;
289
307
  }
290
308
  });
291
- if (localInstantSearchInstance && Boolean(widgets.length)) {
292
- var _widgets$reduce = widgets.reduce(function (states, widget) {
309
+ if (localInstantSearchInstance && Boolean(flatWidgets.length)) {
310
+ var _flatWidgets$reduce = flatWidgets.reduce(function (states, widget) {
293
311
  // the `dispose` method exists at this point we already assert it
294
312
  var next = widget.dispose({
295
313
  helper: helper,
@@ -307,8 +325,8 @@ var index = function index(widgetParams) {
307
325
  cleanedSearchState: helper.state,
308
326
  cleanedRecommendState: helper.recommendState
309
327
  }),
310
- cleanedSearchState = _widgets$reduce.cleanedSearchState,
311
- cleanedRecommendState = _widgets$reduce.cleanedRecommendState;
328
+ cleanedSearchState = _flatWidgets$reduce.cleanedSearchState,
329
+ cleanedRecommendState = _flatWidgets$reduce.cleanedRecommendState;
312
330
  var newState = localInstantSearchInstance.future.preserveSharedStateOnUnmount ? getLocalWidgetsSearchParameters(localWidgets, {
313
331
  uiState: localUiState,
314
332
  initialSearchParameters: new _algoliasearchHelper.default.SearchParameters({
@@ -328,7 +346,12 @@ var index = function index(widgetParams) {
328
346
  helper.setState(newState);
329
347
  helper.recommendState = cleanedRecommendState;
330
348
  if (localWidgets.length) {
331
- localInstantSearchInstance.scheduleSearch();
349
+ if (isolated) {
350
+ var _helper3;
351
+ (_helper3 = helper) === null || _helper3 === void 0 ? void 0 : _helper3.search();
352
+ } else {
353
+ localInstantSearchInstance.scheduleSearch();
354
+ }
332
355
  }
333
356
  }
334
357
  return this;
@@ -366,13 +389,20 @@ var index = function index(widgetParams) {
366
389
  // This Helper is only used for state management we do not care about the
367
390
  // `searchClient`. Only the "main" Helper created at the `InstantSearch`
368
391
  // level is aware of the client.
369
- helper = (0, _algoliasearchHelper.default)({}, parameters.index, parameters);
392
+ helper = (0, _algoliasearchHelper.default)(mainHelper.getClient(), parameters.index, parameters);
370
393
  helper.recommendState = recommendParameters;
371
394
 
372
395
  // We forward the call to `search` to the "main" instance of the Helper
373
396
  // which is responsible for managing the queries (it's the only one that is
374
397
  // aware of the `searchClient`).
375
398
  helper.search = function () {
399
+ if (isolated) {
400
+ instantSearchInstance.status = 'loading';
401
+ _this3.render({
402
+ instantSearchInstance: instantSearchInstance
403
+ });
404
+ return instantSearchInstance.compositionID ? helper.searchWithComposition() : helper.searchOnlyWithDerivedHelpers();
405
+ }
376
406
  if (instantSearchInstance.onStateChange) {
377
407
  instantSearchInstance.onStateChange({
378
408
  uiState: instantSearchInstance.mainIndex.getWidgetUiState({}),
@@ -396,7 +426,9 @@ var index = function index(widgetParams) {
396
426
  var state = helper.state.setQueryParameters(userState);
397
427
  return mainHelper.searchForFacetValues(facetName, facetValue, maxFacetHits, state);
398
428
  };
399
- derivedHelper = mainHelper.derive(function () {
429
+ var isolatedHelper = indexName ? helper : (0, _algoliasearchHelper.default)({}, '__empty_index__', {});
430
+ var derivingHelper = isolated ? isolatedHelper : nearestIsolatedHelper(parent, mainHelper);
431
+ derivedHelper = derivingHelper.derive(function () {
400
432
  return _utils.mergeSearchParameters.apply(void 0, [mainHelper.state].concat(_toConsumableArray((0, _utils.resolveSearchParameters)(_this3))));
401
433
  }, function () {
402
434
  return _this3.getHelper().recommendState;
@@ -538,7 +570,9 @@ var index = function index(widgetParams) {
538
570
 
539
571
  // We only render index widgets if there are no results.
540
572
  // This makes sure `render` is never called with `results` being `null`.
541
- var widgetsToRender = this.getResults() || (_derivedHelper2 = derivedHelper) !== null && _derivedHelper2 !== void 0 && _derivedHelper2.lastRecommendResults ? localWidgets : localWidgets.filter(_utils.isIndexWidget);
573
+ // If it's an isolated index without an index name, we render all widgets,
574
+ // as there are no results to display for the isolated index itself.
575
+ var widgetsToRender = this.getResults() || (_derivedHelper2 = derivedHelper) !== null && _derivedHelper2 !== void 0 && _derivedHelper2.lastRecommendResults || isolated && !indexName ? localWidgets : localWidgets.filter(_utils.isIndexWidget);
542
576
  widgetsToRender = widgetsToRender.filter(function (widget) {
543
577
  if (!widget.shouldRender) {
544
578
  return true;
@@ -572,7 +606,7 @@ var index = function index(widgetParams) {
572
606
  },
573
607
  dispose: function dispose() {
574
608
  var _this5 = this,
575
- _helper2,
609
+ _helper4,
576
610
  _derivedHelper3;
577
611
  localWidgets.forEach(function (widget) {
578
612
  if (widget.dispose && helper) {
@@ -592,13 +626,15 @@ var index = function index(widgetParams) {
592
626
  });
593
627
  localInstantSearchInstance = null;
594
628
  localParent = null;
595
- (_helper2 = helper) === null || _helper2 === void 0 ? void 0 : _helper2.removeAllListeners();
629
+ (_helper4 = helper) === null || _helper4 === void 0 ? void 0 : _helper4.removeAllListeners();
596
630
  helper = null;
597
631
  (_derivedHelper3 = derivedHelper) === null || _derivedHelper3 === void 0 ? void 0 : _derivedHelper3.detach();
598
632
  derivedHelper = null;
599
633
  },
600
634
  getWidgetUiState: function getWidgetUiState(uiState) {
601
- return localWidgets.filter(_utils.isIndexWidget).reduce(function (previousUiState, innerIndex) {
635
+ return localWidgets.filter(_utils.isIndexWidget).filter(function (w) {
636
+ return !w._isolated;
637
+ }).reduce(function (previousUiState, innerIndex) {
602
638
  return innerIndex.getWidgetUiState(previousUiState);
603
639
  }, _objectSpread(_objectSpread({}, uiState), {}, _defineProperty({}, indexId, _objectSpread(_objectSpread({}, uiState[indexId]), localUiState))));
604
640
  },
@@ -634,4 +670,17 @@ function storeRenderState(_ref8) {
634
670
  parent = _ref8.parent;
635
671
  var parentIndexName = parent ? parent.getIndexId() : instantSearchInstance.mainIndex.getIndexId();
636
672
  instantSearchInstance.renderState = _objectSpread(_objectSpread({}, instantSearchInstance.renderState), {}, _defineProperty({}, parentIndexName, _objectSpread(_objectSpread({}, instantSearchInstance.renderState[parentIndexName]), renderState)));
673
+ }
674
+
675
+ /**
676
+ * Walk up the parent chain to find the closest isolated index, or fall back to mainHelper
677
+ */
678
+ function nearestIsolatedHelper(current, mainHelper) {
679
+ while (current) {
680
+ if (current._isolated) {
681
+ return current.getHelper();
682
+ }
683
+ current = current.getParent();
684
+ }
685
+ return mainHelper;
637
686
  }
@@ -4758,8 +4758,8 @@ declare type IndexWidget<TUiState extends UiState = UiState> = Omit<Widget<Index
4758
4758
  getParent: () => IndexWidget | null;
4759
4759
  getWidgets: () => Array<Widget | IndexWidget>;
4760
4760
  createURL: (nextState: SearchParameters | ((state: IndexUiState) => IndexUiState)) => string;
4761
- addWidgets: (widgets: Array<Widget | IndexWidget>) => IndexWidget;
4762
- removeWidgets: (widgets: Array<Widget | IndexWidget>) => IndexWidget;
4761
+ addWidgets: (widgets: Array<Widget | IndexWidget | Widget[]>) => IndexWidget;
4762
+ removeWidgets: (widgets: Array<Widget | IndexWidget | Widget[]>) => IndexWidget;
4763
4763
  init: (options: IndexInitOptions) => void;
4764
4764
  render: (options: IndexRenderOptions) => void;
4765
4765
  dispose: () => void;
@@ -4782,6 +4782,12 @@ declare type IndexWidget<TUiState extends UiState = UiState> = Omit<Widget<Index
4782
4782
  * Can only be called after `init`.
4783
4783
  */
4784
4784
  setIndexUiState: (indexUiState: TUiState[string] | ((previousIndexUiState: TUiState[string]) => TUiState[string])) => void;
4785
+ /**
4786
+ * This index is isolated, meaning it will not be merged with the main
4787
+ * helper's state.
4788
+ * @private
4789
+ */
4790
+ _isolated: boolean;
4785
4791
  };
4786
4792
 
4787
4793
  declare type IndexWidgetDescription = {
@@ -4790,7 +4796,45 @@ declare type IndexWidgetDescription = {
4790
4796
  };
4791
4797
 
4792
4798
  declare type IndexWidgetParams = {
4799
+ /**
4800
+ * The index or composition id to target.
4801
+ */
4793
4802
  indexName: string;
4803
+ /**
4804
+ * Id to use for the index if there are multiple indices with the same name.
4805
+ * This will be used to create the URL and the render state.
4806
+ */
4807
+ indexId?: string;
4808
+ /**
4809
+ * If `true`, the index will not be merged with the main helper's state.
4810
+ * This means that the index will not be part of the main search request.
4811
+ *
4812
+ * @default false
4813
+ */
4814
+ EXPERIMENTAL_isolated?: false;
4815
+ } | {
4816
+ /**
4817
+ * If `true`, the index will not be merged with the main helper's state.
4818
+ * This means that the index will not be part of the main search request.
4819
+ *
4820
+ * This option is EXPERIMENTAL, and implementation details may change in the future.
4821
+ * Things that could change are:
4822
+ * - which widgets get rendered when a change happens
4823
+ * - whether the index searches automatically
4824
+ * - whether the index is included in the URL / UiState
4825
+ * - whether the index is included in server-side rendering
4826
+ *
4827
+ * @default false
4828
+ */
4829
+ EXPERIMENTAL_isolated: true;
4830
+ /**
4831
+ * The index or composition id to target.
4832
+ */
4833
+ indexName?: string;
4834
+ /**
4835
+ * Id to use for the index if there are multiple indices with the same name.
4836
+ * This will be used to create the URL and the render state.
4837
+ */
4794
4838
  indexId?: string;
4795
4839
  };
4796
4840
 
@@ -5125,7 +5169,7 @@ declare class InstantSearch<TUiState extends UiState = UiState, TRouteState = TU
5125
5169
  * Widgets can be added either before or after InstantSearch has started.
5126
5170
  * @param widgets The array of widgets to add to InstantSearch.
5127
5171
  */
5128
- addWidgets(widgets: Array<Widget | IndexWidget>): this;
5172
+ addWidgets(widgets: Array<Widget | IndexWidget | Widget[]>): this;
5129
5173
  /**
5130
5174
  * Removes a widget from the search instance.
5131
5175
  * @deprecated This method will still be supported in 4.x releases, but not further. It is replaced by `removeWidgets([widget])`
@@ -5140,7 +5184,7 @@ declare class InstantSearch<TUiState extends UiState = UiState, TRouteState = TU
5140
5184
  *
5141
5185
  * The widgets must implement a `dispose()` method to clear their states.
5142
5186
  */
5143
- removeWidgets(widgets: Array<Widget | IndexWidget>): this;
5187
+ removeWidgets(widgets: Array<Widget | IndexWidget | Widget[]>): this;
5144
5188
  /**
5145
5189
  * Ends the initialization of InstantSearch.js and triggers the
5146
5190
  * first search.