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.
@@ -38,7 +38,7 @@ function Pagination(props) {
38
38
  }), props.pages.map(function (pageNumber) {
39
39
  return h(PaginationLink, {
40
40
  key: pageNumber,
41
- ariaLabel: "".concat(pageNumber + 1),
41
+ ariaLabel: "Page ".concat(pageNumber + 1),
42
42
  className: props.cssClasses.pageItem,
43
43
  isSelected: pageNumber === props.currentPage,
44
44
  label: "".concat(pageNumber + 1),
@@ -55,7 +55,8 @@ var connectHits = function connectHits(renderFn) {
55
55
  if (!bindEvent) {
56
56
  bindEvent = createBindEventForHits({
57
57
  index: helper.getIndex(),
58
- widgetType: this.$$type
58
+ widgetType: this.$$type,
59
+ instantSearchInstance: instantSearchInstance
59
60
  });
60
61
  }
61
62
  if (!results) {
@@ -145,7 +145,8 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
145
145
  });
146
146
  bindEvent = createBindEventForHits({
147
147
  index: helper.getIndex(),
148
- widgetType: this.$$type
148
+ widgetType: this.$$type,
149
+ instantSearchInstance: instantSearchInstance
149
150
  });
150
151
  isFirstPage = state.page === undefined || getFirstReceivedPage(state, cachedHits) === 0;
151
152
  } else {
@@ -159,7 +160,7 @@ var connectInfiniteHits = function connectInfiniteHits(renderFn) {
159
160
  var transformedHits = transformItems(hitsWithAbsolutePositionAndQueryID, {
160
161
  results: results
161
162
  });
162
- if (cachedHits[_page] === undefined && !results.__isArtificial) {
163
+ if (cachedHits[_page] === undefined && !results.__isArtificial && instantSearchInstance.status === 'idle') {
163
164
  cachedHits[_page] = transformedHits;
164
165
  cache.write({
165
166
  state: state,
@@ -73,8 +73,9 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
73
73
  }
74
74
  }));
75
75
  _defineProperty(_assertThisInitialized(_this), "scheduleRender", defer(function () {
76
+ var _this$mainHelper;
76
77
  var shouldResetStatus = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
77
- if (!_this.mainHelper.hasPendingRequests()) {
78
+ if (!((_this$mainHelper = _this.mainHelper) !== null && _this$mainHelper !== void 0 && _this$mainHelper.hasPendingRequests())) {
78
79
  clearTimeout(_this._searchStalledTimer);
79
80
  _this._searchStalledTimer = null;
80
81
  if (shouldResetStatus) {
@@ -342,12 +343,7 @@ var InstantSearch = /*#__PURE__*/function (_EventEmitter) {
342
343
  var mainHelper = this.mainHelper || algoliasearchHelper(this.client, this.indexName);
343
344
  mainHelper.search = function () {
344
345
  _this3.status = 'loading';
345
- // @MAJOR: use scheduleRender here
346
- // For now, widgets don't expect to be rendered at the start of `loading`,
347
- // so it would be a breaking change to add an extra render. We don't have
348
- // these guarantees about the render event, thus emitting it once more
349
- // isn't a breaking change.
350
- _this3.emit('render');
346
+ _this3.scheduleRender(false);
351
347
 
352
348
  // This solution allows us to keep the exact same API for the users but
353
349
  // under the hood, we have a different implementation. It should be
@@ -50,6 +50,9 @@ export function renderTemplate(_ref) {
50
50
  Snippet: Snippet,
51
51
  ReverseSnippet: ReverseSnippet
52
52
  };
53
+
54
+ // @MAJOR remove the `as any` when string templates are removed
55
+ // needed because not every template receives sendEvent
53
56
  return template(data, params);
54
57
  }
55
58
  var transformedHelpers = transformHelpersToHogan(helpers, compileOptions, data);
@@ -2,16 +2,17 @@ import type { InstantSearch, Hit } from '../../types';
2
2
  declare type BuiltInSendEventForHits = (eventType: string, hits: Hit | Hit[], eventName?: string) => void;
3
3
  declare type CustomSendEventForHits = (customPayload: any) => void;
4
4
  export declare type SendEventForHits = BuiltInSendEventForHits & CustomSendEventForHits;
5
- declare type BuiltInBindEventForHits = (eventType: string, hits: Hit | Hit[], eventName?: string) => string;
6
- declare type CustomBindEventForHits = (customPayload: any) => string;
5
+ export declare type BuiltInBindEventForHits = (eventType: string, hits: Hit | Hit[], eventName?: string) => string;
6
+ export declare type CustomBindEventForHits = (customPayload: any) => string;
7
7
  export declare type BindEventForHits = BuiltInBindEventForHits & CustomBindEventForHits;
8
8
  export declare function createSendEventForHits({ instantSearchInstance, index, widgetType, }: {
9
9
  instantSearchInstance: InstantSearch;
10
10
  index: string;
11
11
  widgetType: string;
12
12
  }): SendEventForHits;
13
- export declare function createBindEventForHits({ index, widgetType, }: {
13
+ export declare function createBindEventForHits({ index, widgetType, instantSearchInstance, }: {
14
14
  index: string;
15
15
  widgetType: string;
16
+ instantSearchInstance: InstantSearch;
16
17
  }): BindEventForHits;
17
18
  export {};
@@ -13,7 +13,7 @@ var buildPayloads = function buildPayloads(_ref) {
13
13
  widgetType = _ref.widgetType,
14
14
  methodName = _ref.methodName,
15
15
  args = _ref.args,
16
- isSearchStalled = _ref.isSearchStalled;
16
+ instantSearchInstance = _ref.instantSearchInstance;
17
17
  // when there's only one argument, that means it's custom
18
18
  if (args.length === 1 && _typeof(args[0]) === 'object') {
19
19
  return [args[0]];
@@ -52,7 +52,7 @@ var buildPayloads = function buildPayloads(_ref) {
52
52
  });
53
53
  });
54
54
  if (eventType === 'view') {
55
- if (isSearchStalled) {
55
+ if (instantSearchInstance.status !== 'idle') {
56
56
  return [];
57
57
  }
58
58
  return hitsChunks.map(function (batch, i) {
@@ -122,7 +122,7 @@ export function createSendEventForHits(_ref2) {
122
122
  index: index,
123
123
  methodName: 'sendEvent',
124
124
  args: args,
125
- isSearchStalled: instantSearchInstance.status === 'stalled'
125
+ instantSearchInstance: instantSearchInstance
126
126
  });
127
127
  payloads.forEach(function (payload) {
128
128
  return instantSearchInstance.sendEventToInsights(payload);
@@ -132,7 +132,8 @@ export function createSendEventForHits(_ref2) {
132
132
  }
133
133
  export function createBindEventForHits(_ref3) {
134
134
  var index = _ref3.index,
135
- widgetType = _ref3.widgetType;
135
+ widgetType = _ref3.widgetType,
136
+ instantSearchInstance = _ref3.instantSearchInstance;
136
137
  var bindEventForHits = function bindEventForHits() {
137
138
  for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
138
139
  args[_key2] = arguments[_key2];
@@ -142,7 +143,7 @@ export function createBindEventForHits(_ref3) {
142
143
  index: index,
143
144
  methodName: 'bindEvent',
144
145
  args: args,
145
- isSearchStalled: false
146
+ instantSearchInstance: instantSearchInstance
146
147
  });
147
148
  return payloads.length ? "data-insights-event=".concat(serializePayload(payloads)) : '';
148
149
  };
@@ -1,2 +1,2 @@
1
- declare const _default: "4.49.4";
1
+ declare const _default: "4.50.0";
2
2
  export default _default;
package/es/lib/version.js CHANGED
@@ -1 +1 @@
1
- export default '4.49.4';
1
+ export default '4.50.0';
@@ -1,9 +1,9 @@
1
1
  import type { VNode } from 'preact';
2
2
  import type { Highlight, ReverseHighlight, ReverseSnippet, Snippet } from '../helpers/components';
3
3
  import type { html } from 'htm/preact';
4
- import type { BindEventForHits, SendEventForHits } from '../lib/utils';
4
+ import type { BuiltInBindEventForHits, CustomBindEventForHits, SendEventForHits } from '../lib/utils';
5
5
  export declare type Template<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string);
6
- export declare type TemplateParams = BindEventForHits & {
6
+ export declare type TemplateParams = {
7
7
  html: typeof html;
8
8
  components: {
9
9
  Highlight: typeof Highlight;
@@ -13,8 +13,16 @@ export declare type TemplateParams = BindEventForHits & {
13
13
  };
14
14
  sendEvent?: SendEventForHits;
15
15
  };
16
- export declare type TemplateWithBindEvent<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateParams) => VNode | VNode[] | string);
16
+ interface TemplateWithBindEventParams extends TemplateParams {
17
+ /** @deprecated use sendEvent instead */
18
+ (...args: Parameters<BuiltInBindEventForHits>): ReturnType<BuiltInBindEventForHits>;
19
+ /** @deprecated use sendEvent instead */
20
+ (...args: Parameters<CustomBindEventForHits>): ReturnType<CustomBindEventForHits>;
21
+ sendEvent: SendEventForHits;
22
+ }
23
+ export declare type TemplateWithBindEvent<TTemplateData = void> = string | ((data: TTemplateData, params: TemplateWithBindEventParams) => VNode | VNode[] | string);
17
24
  export declare type Templates = {
18
25
  [key: string]: Template<any> | TemplateWithBindEvent<any> | undefined;
19
26
  };
20
27
  export declare type HoganHelpers<TKeys extends string = string> = Record<TKeys, (text: string, render: (value: string) => string) => string>;
28
+ export {};
@@ -101,6 +101,7 @@ var index = function index(widgetParams) {
101
101
  var localParent = null;
102
102
  var helper = null;
103
103
  var derivedHelper = null;
104
+ var lastValidSearchParameters = null;
104
105
  return {
105
106
  $$type: 'ais.index',
106
107
  $$widgetType: 'ais.index',
@@ -114,7 +115,16 @@ var index = function index(widgetParams) {
114
115
  return helper;
115
116
  },
116
117
  getResults: function getResults() {
117
- return derivedHelper && derivedHelper.lastResults;
118
+ var _derivedHelper;
119
+ if (!((_derivedHelper = derivedHelper) !== null && _derivedHelper !== void 0 && _derivedHelper.lastResults)) return null;
120
+
121
+ // To make the UI optimistic, we patch the state to display to the current
122
+ // one instead of the one associated with the latest results.
123
+ // This means user-driven UI changes (e.g., checked checkbox) are reflected
124
+ // immediately instead of waiting for Algolia to respond, regardless of
125
+ // the status of the network request.
126
+ derivedHelper.lastResults._state = helper.state;
127
+ return derivedHelper.lastResults;
118
128
  },
119
129
  getScopedResults: function getScopedResults() {
120
130
  var widgetParent = this.getParent();
@@ -319,6 +329,7 @@ var index = function index(widgetParams) {
319
329
  // does not have access to lastResults, which it used to in pre-federated
320
330
  // search behavior.
321
331
  helper.lastResults = results;
332
+ lastValidSearchParameters = results._state;
322
333
  });
323
334
 
324
335
  // We compute the render state before calling `init` in a separate loop
@@ -377,6 +388,12 @@ var index = function index(widgetParams) {
377
388
  if (!this.getResults()) {
378
389
  return;
379
390
  }
391
+
392
+ // we can't attach a listener to the error event of search, as the error
393
+ // then would no longer be thrown for global handlers.
394
+ if (instantSearchInstance.status === 'error' && !instantSearchInstance.mainHelper.hasPendingRequests()) {
395
+ helper.setState(lastValidSearchParameters);
396
+ }
380
397
  localWidgets.forEach(function (widget) {
381
398
  if (widget.getRenderState) {
382
399
  var renderState = widget.getRenderState(instantSearchInstance.renderState[_this4.getIndexId()] || {}, createRenderArgs(instantSearchInstance, _this4));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instantsearch.js",
3
- "version": "4.49.4",
3
+ "version": "4.50.0",
4
4
  "description": "InstantSearch.js is a JavaScript library for building performant and instant search experiences with Algolia.",
5
5
  "homepage": "https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/",
6
6
  "types": "es/index.d.ts",
@@ -32,7 +32,7 @@
32
32
  "@types/google.maps": "^3.45.3",
33
33
  "@types/hogan.js": "^3.0.0",
34
34
  "@types/qs": "^6.5.3",
35
- "algoliasearch-helper": "^3.11.2",
35
+ "algoliasearch-helper": "^3.11.3",
36
36
  "hogan.js": "^3.0.2",
37
37
  "htm": "^3.0.0",
38
38
  "preact": "^10.10.0",
@@ -54,8 +54,9 @@
54
54
  "version": "./scripts/version/update-version.js"
55
55
  },
56
56
  "devDependencies": {
57
- "@instantsearch/mocks": "1.0.3",
58
- "@instantsearch/testutils": "1.0.3",
57
+ "@instantsearch/mocks": "1.1.0",
58
+ "@instantsearch/tests": "1.1.0",
59
+ "@instantsearch/testutils": "1.0.4",
59
60
  "@storybook/html": "5.3.9",
60
61
  "@types/scriptjs": "0.0.2",
61
62
  "algoliasearch": "4.14.3",
@@ -63,5 +64,5 @@
63
64
  "scriptjs": "2.5.9",
64
65
  "webpack": "4.41.5"
65
66
  },
66
- "gitHead": "4c473604508a865a2488e064fdd3a415f416d14a"
67
+ "gitHead": "15adccb907fec9528ab169ee3d7d905ceab5a860"
67
68
  }