@algolia/autocomplete-core 1.2.2 → 1.5.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 (52) hide show
  1. package/dist/esm/createAutocomplete.d.ts +8 -2
  2. package/dist/esm/createAutocomplete.js +9 -1
  3. package/dist/esm/createStore.js +1 -1
  4. package/dist/esm/getAutocompleteSetters.js +2 -2
  5. package/dist/esm/getDefaultProps.js +14 -10
  6. package/dist/esm/getPropGetters.js +16 -10
  7. package/dist/esm/index.d.ts +0 -1
  8. package/dist/esm/index.js +1 -2
  9. package/dist/esm/metadata.d.ts +33 -0
  10. package/dist/esm/metadata.js +44 -0
  11. package/dist/esm/onInput.js +59 -37
  12. package/dist/esm/onKeyDown.js +4 -2
  13. package/dist/esm/reshape.d.ts +11 -0
  14. package/dist/esm/reshape.js +34 -0
  15. package/dist/esm/resolve.js +7 -5
  16. package/dist/esm/stateReducer.js +1 -1
  17. package/dist/esm/types/AutocompleteApi.js +1 -0
  18. package/dist/esm/types/AutocompleteCollection.js +1 -0
  19. package/dist/esm/types/AutocompleteContext.js +1 -0
  20. package/dist/esm/types/AutocompleteEnvironment.d.ts +1 -0
  21. package/dist/esm/types/AutocompleteEnvironment.js +1 -0
  22. package/dist/esm/types/AutocompleteNavigator.js +1 -0
  23. package/dist/esm/types/AutocompleteOptions.d.ts +12 -0
  24. package/dist/esm/types/AutocompleteOptions.js +1 -0
  25. package/dist/esm/types/AutocompletePlugin.d.ts +10 -0
  26. package/dist/esm/types/AutocompletePlugin.js +1 -0
  27. package/dist/esm/types/AutocompletePropGetters.js +1 -0
  28. package/dist/esm/types/AutocompleteReshape.d.ts +23 -0
  29. package/dist/esm/types/AutocompleteReshape.js +1 -0
  30. package/dist/esm/types/AutocompleteSetters.js +1 -0
  31. package/dist/esm/types/AutocompleteSource.js +1 -0
  32. package/dist/esm/types/AutocompleteState.js +1 -0
  33. package/dist/esm/types/AutocompleteStore.js +1 -0
  34. package/dist/esm/types/AutocompleteSubscribers.js +1 -0
  35. package/dist/esm/types/index.d.ts +1 -0
  36. package/dist/esm/types/index.js +1 -0
  37. package/dist/esm/utils/createConcurrentSafePromise.d.ts +1 -1
  38. package/dist/esm/utils/getNormalizedSources.js +5 -4
  39. package/dist/esm/utils/index.d.ts +0 -2
  40. package/dist/esm/utils/index.js +1 -3
  41. package/dist/esm/utils/mapToAlgoliaResponse.js +1 -1
  42. package/dist/umd/index.development.js +411 -148
  43. package/dist/umd/index.development.js.map +1 -1
  44. package/dist/umd/index.production.js +2 -2
  45. package/dist/umd/index.production.js.map +1 -1
  46. package/package.json +3 -3
  47. package/dist/esm/utils/flatten.d.ts +0 -1
  48. package/dist/esm/utils/flatten.js +0 -5
  49. package/dist/esm/utils/noop.d.ts +0 -1
  50. package/dist/esm/utils/noop.js +0 -1
  51. package/dist/esm/version.d.ts +0 -1
  52. package/dist/esm/version.js +0 -1
@@ -1,49 +1,22 @@
1
- /*! @algolia/autocomplete-core 1.2.2 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
1
+ /*! @algolia/autocomplete-core 1.5.0 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
2
2
  (function (global, factory) {
3
3
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
4
4
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
5
5
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['@algolia/autocomplete-core'] = {}));
6
6
  }(this, (function (exports) { 'use strict';
7
7
 
8
- function _typeof(obj) {
9
- "@babel/helpers - typeof";
10
-
11
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
12
- _typeof = function (obj) {
13
- return typeof obj;
14
- };
15
- } else {
16
- _typeof = function (obj) {
17
- return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
18
- };
19
- }
20
-
21
- return _typeof(obj);
22
- }
23
-
24
- function _defineProperty(obj, key, value) {
25
- if (key in obj) {
26
- Object.defineProperty(obj, key, {
27
- value: value,
28
- enumerable: true,
29
- configurable: true,
30
- writable: true
31
- });
32
- } else {
33
- obj[key] = value;
34
- }
35
-
36
- return obj;
37
- }
38
-
39
8
  function ownKeys(object, enumerableOnly) {
40
9
  var keys = Object.keys(object);
41
10
 
42
11
  if (Object.getOwnPropertySymbols) {
43
12
  var symbols = Object.getOwnPropertySymbols(object);
44
- if (enumerableOnly) symbols = symbols.filter(function (sym) {
45
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
46
- });
13
+
14
+ if (enumerableOnly) {
15
+ symbols = symbols.filter(function (sym) {
16
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
17
+ });
18
+ }
19
+
47
20
  keys.push.apply(keys, symbols);
48
21
  }
49
22
 
@@ -70,6 +43,37 @@
70
43
  return target;
71
44
  }
72
45
 
46
+ function _typeof(obj) {
47
+ "@babel/helpers - typeof";
48
+
49
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
50
+ _typeof = function (obj) {
51
+ return typeof obj;
52
+ };
53
+ } else {
54
+ _typeof = function (obj) {
55
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
56
+ };
57
+ }
58
+
59
+ return _typeof(obj);
60
+ }
61
+
62
+ function _defineProperty(obj, key, value) {
63
+ if (key in obj) {
64
+ Object.defineProperty(obj, key, {
65
+ value: value,
66
+ enumerable: true,
67
+ configurable: true,
68
+ writable: true
69
+ });
70
+ } else {
71
+ obj[key] = value;
72
+ }
73
+
74
+ return obj;
75
+ }
76
+
73
77
  function _objectWithoutPropertiesLoose(source, excluded) {
74
78
  if (source == null) return {};
75
79
  var target = {};
@@ -115,7 +119,7 @@
115
119
  }
116
120
 
117
121
  function _iterableToArray(iter) {
118
- if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
122
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
119
123
  }
120
124
 
121
125
  function _unsupportedIterableToArray(o, minLen) {
@@ -139,6 +143,122 @@
139
143
  throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
140
144
  }
141
145
 
146
+ function _slicedToArray(arr, i) {
147
+ return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray$1(arr, i) || _nonIterableRest();
148
+ }
149
+
150
+ function _nonIterableRest() {
151
+ throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
152
+ }
153
+
154
+ function _unsupportedIterableToArray$1(o, minLen) {
155
+ if (!o) return;
156
+ if (typeof o === "string") return _arrayLikeToArray$1(o, minLen);
157
+ var n = Object.prototype.toString.call(o).slice(8, -1);
158
+ if (n === "Object" && o.constructor) n = o.constructor.name;
159
+ if (n === "Map" || n === "Set") return Array.from(o);
160
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray$1(o, minLen);
161
+ }
162
+
163
+ function _arrayLikeToArray$1(arr, len) {
164
+ if (len == null || len > arr.length) len = arr.length;
165
+
166
+ for (var i = 0, arr2 = new Array(len); i < len; i++) {
167
+ arr2[i] = arr[i];
168
+ }
169
+
170
+ return arr2;
171
+ }
172
+
173
+ function _iterableToArrayLimit(arr, i) {
174
+ var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"];
175
+
176
+ if (_i == null) return;
177
+ var _arr = [];
178
+ var _n = true;
179
+ var _d = false;
180
+
181
+ var _s, _e;
182
+
183
+ try {
184
+ for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) {
185
+ _arr.push(_s.value);
186
+
187
+ if (i && _arr.length === i) break;
188
+ }
189
+ } catch (err) {
190
+ _d = true;
191
+ _e = err;
192
+ } finally {
193
+ try {
194
+ if (!_n && _i["return"] != null) _i["return"]();
195
+ } finally {
196
+ if (_d) throw _e;
197
+ }
198
+ }
199
+
200
+ return _arr;
201
+ }
202
+
203
+ function _arrayWithHoles(arr) {
204
+ if (Array.isArray(arr)) return arr;
205
+ }
206
+
207
+ function _typeof$1(obj) {
208
+ "@babel/helpers - typeof";
209
+
210
+ if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
211
+ _typeof$1 = function _typeof(obj) {
212
+ return typeof obj;
213
+ };
214
+ } else {
215
+ _typeof$1 = function _typeof(obj) {
216
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
217
+ };
218
+ }
219
+
220
+ return _typeof$1(obj);
221
+ }
222
+ /**
223
+ * Decycles objects with circular references.
224
+ * This is used to print cyclic structures in development environment only.
225
+ */
226
+
227
+
228
+ function decycle(obj) {
229
+ var seen = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new Set();
230
+
231
+ if ( !obj || _typeof$1(obj) !== 'object') {
232
+ return obj;
233
+ }
234
+
235
+ if (seen.has(obj)) {
236
+ return '[Circular]';
237
+ }
238
+
239
+ var newSeen = seen.add(obj);
240
+
241
+ if (Array.isArray(obj)) {
242
+ return obj.map(function (x) {
243
+ return decycle(x, newSeen);
244
+ });
245
+ }
246
+
247
+ return Object.fromEntries(Object.entries(obj).map(function (_ref) {
248
+ var _ref2 = _slicedToArray(_ref, 2),
249
+ key = _ref2[0],
250
+ value = _ref2[1];
251
+
252
+ return [key, decycle(value, newSeen)];
253
+ }));
254
+ }
255
+
256
+ function flatten(values) {
257
+ return values.reduce(function (a, b) {
258
+ return a.concat(b);
259
+ }, []);
260
+ }
261
+
142
262
  var autocompleteId = 0;
143
263
  function generateAutocompleteId() {
144
264
  return "autocomplete-".concat(autocompleteId++);
@@ -162,10 +282,19 @@
162
282
  function invariant(condition, message) {
163
283
 
164
284
  if (!condition) {
165
- throw new Error("[Autocomplete] ".concat(message));
285
+ throw new Error("[Autocomplete] ".concat(typeof message === 'function' ? message() : message));
166
286
  }
167
287
  }
168
288
 
289
+ var noop = function noop() {};
290
+
291
+ var version = '1.5.0';
292
+
293
+ var userAgents = [{
294
+ segment: 'autocomplete-core',
295
+ version: version
296
+ }];
297
+
169
298
  var warnCache = {
170
299
  current: {}
171
300
  };
@@ -216,10 +345,91 @@
216
345
  };
217
346
  }
218
347
 
219
- function flatten(values) {
220
- return values.reduce(function (a, b) {
221
- return a.concat(b);
222
- }, []);
348
+ function getAutocompleteSetters(_ref) {
349
+ var store = _ref.store;
350
+
351
+ var setActiveItemId = function setActiveItemId(value) {
352
+ store.dispatch('setActiveItemId', value);
353
+ };
354
+
355
+ var setQuery = function setQuery(value) {
356
+ store.dispatch('setQuery', value);
357
+ };
358
+
359
+ var setCollections = function setCollections(rawValue) {
360
+ var baseItemId = 0;
361
+ var value = rawValue.map(function (collection) {
362
+ return _objectSpread2(_objectSpread2({}, collection), {}, {
363
+ // We flatten the stored items to support calling `getAlgoliaResults`
364
+ // from the source itself.
365
+ items: flatten(collection.items).map(function (item) {
366
+ return _objectSpread2(_objectSpread2({}, item), {}, {
367
+ __autocomplete_id: baseItemId++
368
+ });
369
+ })
370
+ });
371
+ });
372
+ store.dispatch('setCollections', value);
373
+ };
374
+
375
+ var setIsOpen = function setIsOpen(value) {
376
+ store.dispatch('setIsOpen', value);
377
+ };
378
+
379
+ var setStatus = function setStatus(value) {
380
+ store.dispatch('setStatus', value);
381
+ };
382
+
383
+ var setContext = function setContext(value) {
384
+ store.dispatch('setContext', value);
385
+ };
386
+
387
+ return {
388
+ setActiveItemId: setActiveItemId,
389
+ setQuery: setQuery,
390
+ setCollections: setCollections,
391
+ setIsOpen: setIsOpen,
392
+ setStatus: setStatus,
393
+ setContext: setContext
394
+ };
395
+ }
396
+
397
+ /**
398
+ * Creates a runner that executes promises in a concurrent-safe way.
399
+ *
400
+ * This is useful to prevent older promises to resolve after a newer promise,
401
+ * otherwise resulting in stale resolved values.
402
+ */
403
+ function createConcurrentSafePromise() {
404
+ var basePromiseId = -1;
405
+ var latestResolvedId = -1;
406
+ var latestResolvedValue = undefined;
407
+ return function runConcurrentSafePromise(promise) {
408
+ basePromiseId++;
409
+ var currentPromiseId = basePromiseId;
410
+ return Promise.resolve(promise).then(function (x) {
411
+ // The promise might take too long to resolve and get outdated. This would
412
+ // result in resolving stale values.
413
+ // When this happens, we ignore the promise value and return the one
414
+ // coming from the latest resolved value.
415
+ //
416
+ // +----------------------------------+
417
+ // | 100ms |
418
+ // | run(1) +---> R1 |
419
+ // | 300ms |
420
+ // | run(2) +-------------> R2 (SKIP) |
421
+ // | 200ms |
422
+ // | run(3) +--------> R3 |
423
+ // +----------------------------------+
424
+ if (latestResolvedValue && currentPromiseId < latestResolvedId) {
425
+ return latestResolvedValue;
426
+ }
427
+
428
+ latestResolvedId = currentPromiseId;
429
+ latestResolvedValue = x;
430
+ return x;
431
+ });
432
+ };
223
433
  }
224
434
 
225
435
  /**
@@ -256,12 +466,12 @@
256
466
  return numericIndex;
257
467
  }
258
468
 
259
- var noop = function noop() {};
260
-
261
469
  function getNormalizedSources(getSources, params) {
262
470
  var seenSourceIds = [];
263
471
  return Promise.resolve(getSources(params)).then(function (sources) {
264
- invariant(Array.isArray(sources), "The `getSources` function must return an array of sources but returned type ".concat(JSON.stringify(_typeof(sources)), ":\n\n").concat(JSON.stringify(sources, null, 2)));
472
+ invariant(Array.isArray(sources), function () {
473
+ return "The `getSources` function must return an array of sources but returned type ".concat(JSON.stringify(_typeof(sources)), ":\n\n").concat(JSON.stringify(decycle(sources), null, 2));
474
+ });
265
475
  return Promise.all(sources // We allow `undefined` and `false` sources to allow users to use
266
476
  // `Boolean(query) && source` (=> `false`).
267
477
  // We need to remove these values at this point.
@@ -424,55 +634,6 @@
424
634
  };
425
635
  }
426
636
 
427
- function getAutocompleteSetters(_ref) {
428
- var store = _ref.store;
429
-
430
- var setActiveItemId = function setActiveItemId(value) {
431
- store.dispatch('setActiveItemId', value);
432
- };
433
-
434
- var setQuery = function setQuery(value) {
435
- store.dispatch('setQuery', value);
436
- };
437
-
438
- var setCollections = function setCollections(rawValue) {
439
- var baseItemId = 0;
440
- var value = rawValue.map(function (collection) {
441
- return _objectSpread2(_objectSpread2({}, collection), {}, {
442
- // We flatten the stored items to support calling `getAlgoliaResults`
443
- // from the source itself.
444
- items: flatten(collection.items).map(function (item) {
445
- return _objectSpread2(_objectSpread2({}, item), {}, {
446
- __autocomplete_id: baseItemId++
447
- });
448
- })
449
- });
450
- });
451
- store.dispatch('setCollections', value);
452
- };
453
-
454
- var setIsOpen = function setIsOpen(value) {
455
- store.dispatch('setIsOpen', value);
456
- };
457
-
458
- var setStatus = function setStatus(value) {
459
- store.dispatch('setStatus', value);
460
- };
461
-
462
- var setContext = function setContext(value) {
463
- store.dispatch('setContext', value);
464
- };
465
-
466
- return {
467
- setActiveItemId: setActiveItemId,
468
- setQuery: setQuery,
469
- setCollections: setCollections,
470
- setIsOpen: setIsOpen,
471
- setStatus: setStatus,
472
- setContext: setContext
473
- };
474
- }
475
-
476
637
  function getDefaultProps(props, pluginSubscribers) {
477
638
  var _props$id;
478
639
 
@@ -492,6 +653,10 @@
492
653
  shouldPanelOpen: function shouldPanelOpen(_ref) {
493
654
  var state = _ref.state;
494
655
  return getItemsCount(state) > 0;
656
+ },
657
+ reshape: function reshape(_ref2) {
658
+ var sources = _ref2.sources;
659
+ return sources;
495
660
  }
496
661
  }, props), {}, {
497
662
  // Since `generateAutocompleteId` triggers a side effect (it increments
@@ -569,23 +734,51 @@
569
734
  });
570
735
  },
571
736
  navigator: _objectSpread2({
572
- navigate: function navigate(_ref2) {
573
- var itemUrl = _ref2.itemUrl;
737
+ navigate: function navigate(_ref3) {
738
+ var itemUrl = _ref3.itemUrl;
574
739
  environment.location.assign(itemUrl);
575
740
  },
576
- navigateNewTab: function navigateNewTab(_ref3) {
577
- var itemUrl = _ref3.itemUrl;
741
+ navigateNewTab: function navigateNewTab(_ref4) {
742
+ var itemUrl = _ref4.itemUrl;
578
743
  var windowReference = environment.open(itemUrl, '_blank', 'noopener');
579
744
  windowReference === null || windowReference === void 0 ? void 0 : windowReference.focus();
580
745
  },
581
- navigateNewWindow: function navigateNewWindow(_ref4) {
582
- var itemUrl = _ref4.itemUrl;
746
+ navigateNewWindow: function navigateNewWindow(_ref5) {
747
+ var itemUrl = _ref5.itemUrl;
583
748
  environment.open(itemUrl, '_blank', 'noopener');
584
749
  }
585
750
  }, props.navigator)
586
751
  });
587
752
  }
588
753
 
754
+ function reshape(_ref) {
755
+ var collections = _ref.collections,
756
+ props = _ref.props,
757
+ state = _ref.state;
758
+ // Sources are grouped by `sourceId` to conveniently pick them via destructuring.
759
+ // Example: `const { recentSearchesPlugin } = sourcesBySourceId`
760
+ var sourcesBySourceId = collections.reduce(function (acc, collection) {
761
+ return _objectSpread2(_objectSpread2({}, acc), {}, _defineProperty({}, collection.source.sourceId, _objectSpread2(_objectSpread2({}, collection.source), {}, {
762
+ getItems: function getItems() {
763
+ // We provide the resolved items from the collection to the `reshape` prop.
764
+ return flatten(collection.items);
765
+ }
766
+ })));
767
+ }, {});
768
+ var reshapeSources = props.reshape({
769
+ sources: Object.values(sourcesBySourceId),
770
+ sourcesBySourceId: sourcesBySourceId,
771
+ state: state
772
+ }); // We reconstruct the collections with the items modified by the `reshape` prop.
773
+
774
+ return flatten(reshapeSources).filter(Boolean).map(function (source) {
775
+ return {
776
+ source: source,
777
+ items: source.getItems()
778
+ };
779
+ });
780
+ }
781
+
589
782
  function isDescription(item) {
590
783
  return Boolean(item.execute);
591
784
  }
@@ -670,7 +863,9 @@
670
863
  });
671
864
  var transform = matches[0].transformResponse;
672
865
  var items = transform ? transform(mapToAlgoliaResponse(results)) : results;
673
- invariant(Array.isArray(items), "The `getItems` function from source \"".concat(source.sourceId, "\" must return an array of items but returned type ").concat(JSON.stringify(_typeof(items)), ":\n\n").concat(JSON.stringify(items, null, 2), ".\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"));
866
+ invariant(Array.isArray(items), function () {
867
+ return "The `getItems` function from source \"".concat(source.sourceId, "\" must return an array of items but returned type ").concat(JSON.stringify(_typeof(items)), ":\n\n").concat(JSON.stringify(decycle(items), null, 2), ".\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems");
868
+ });
674
869
  invariant(items.every(Boolean), "The `getItems` function from source \"".concat(source.sourceId, "\" must return an array of items but returned ").concat(JSON.stringify(undefined), ".\n\nDid you forget to return items?\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"));
675
870
  return {
676
871
  source: source,
@@ -679,7 +874,9 @@
679
874
  });
680
875
  }
681
876
 
877
+ var _excluded = ["event", "nextState", "props", "query", "refresh", "store"];
682
878
  var lastStalledId = null;
879
+ var runConcurrentSafePromise = createConcurrentSafePromise();
683
880
  function onInput(_ref) {
684
881
  var event = _ref.event,
685
882
  _ref$nextState = _ref.nextState,
@@ -688,7 +885,7 @@
688
885
  query = _ref.query,
689
886
  refresh = _ref.refresh,
690
887
  store = _ref.store,
691
- setters = _objectWithoutProperties(_ref, ["event", "nextState", "props", "query", "refresh", "store"]);
888
+ setters = _objectWithoutProperties(_ref, _excluded);
692
889
 
693
890
  if (lastStalledId) {
694
891
  props.environment.clearTimeout(lastStalledId);
@@ -705,28 +902,40 @@
705
902
  if (!query && props.openOnFocus === false) {
706
903
  var _nextState$isOpen;
707
904
 
708
- setStatus('idle');
709
- setCollections(store.getState().collections.map(function (collection) {
905
+ var collections = store.getState().collections.map(function (collection) {
710
906
  return _objectSpread2(_objectSpread2({}, collection), {}, {
711
907
  items: []
712
908
  });
713
- }));
909
+ });
910
+ setStatus('idle');
911
+ setCollections(collections);
714
912
  setIsOpen((_nextState$isOpen = nextState.isOpen) !== null && _nextState$isOpen !== void 0 ? _nextState$isOpen : props.shouldPanelOpen({
715
913
  state: store.getState()
716
- }));
717
- return Promise.resolve();
914
+ })); // We make sure to update the latest resolved value of the tracked
915
+ // promises to keep late resolving promises from "cancelling" the state
916
+ // updates performed in this code path.
917
+ // We chain with a void promise to respect `onInput`'s expected return type.
918
+
919
+ return runConcurrentSafePromise(collections).then(function () {
920
+ return Promise.resolve();
921
+ });
718
922
  }
719
923
 
720
924
  setStatus('loading');
721
925
  lastStalledId = props.environment.setTimeout(function () {
722
926
  setStatus('stalled');
723
- }, props.stallThreshold);
724
- return props.getSources(_objectSpread2({
927
+ }, props.stallThreshold); // We track the entire promise chain triggered by `onInput` before mutating
928
+ // the Autocomplete state to make sure that any state manipulation is based on
929
+ // fresh data regardless of when promises individually resolve.
930
+ // We don't track nested promises and only rely on the full chain resolution,
931
+ // meaning we should only ever manipulate the state once this concurrent-safe
932
+ // promise is resolved.
933
+
934
+ return runConcurrentSafePromise(props.getSources(_objectSpread2({
725
935
  query: query,
726
936
  refresh: refresh,
727
937
  state: store.getState()
728
938
  }, setters)).then(function (sources) {
729
- setStatus('loading');
730
939
  return Promise.all(sources.map(function (source) {
731
940
  return Promise.resolve(source.getItems(_objectSpread2({
732
941
  query: query,
@@ -738,45 +947,52 @@
738
947
  })).then(resolve).then(function (responses) {
739
948
  return postResolve(responses, sources);
740
949
  }).then(function (collections) {
741
- var _nextState$isOpen2;
742
-
743
- setStatus('idle');
744
- setCollections(collections);
745
- var isPanelOpen = props.shouldPanelOpen({
950
+ return reshape({
951
+ collections: collections,
952
+ props: props,
746
953
  state: store.getState()
747
954
  });
748
- setIsOpen((_nextState$isOpen2 = nextState.isOpen) !== null && _nextState$isOpen2 !== void 0 ? _nextState$isOpen2 : props.openOnFocus && !query && isPanelOpen || isPanelOpen);
749
- var highlightedItem = getActiveItem(store.getState());
955
+ });
956
+ })).then(function (collections) {
957
+ var _nextState$isOpen2;
750
958
 
751
- if (store.getState().activeItemId !== null && highlightedItem) {
752
- var item = highlightedItem.item,
753
- itemInputValue = highlightedItem.itemInputValue,
754
- itemUrl = highlightedItem.itemUrl,
755
- source = highlightedItem.source;
756
- source.onActive(_objectSpread2({
757
- event: event,
758
- item: item,
759
- itemInputValue: itemInputValue,
760
- itemUrl: itemUrl,
761
- refresh: refresh,
762
- source: source,
763
- state: store.getState()
764
- }, setters));
765
- }
766
- }).finally(function () {
767
- if (lastStalledId) {
768
- props.environment.clearTimeout(lastStalledId);
769
- }
959
+ setStatus('idle');
960
+ setCollections(collections);
961
+ var isPanelOpen = props.shouldPanelOpen({
962
+ state: store.getState()
770
963
  });
964
+ setIsOpen((_nextState$isOpen2 = nextState.isOpen) !== null && _nextState$isOpen2 !== void 0 ? _nextState$isOpen2 : props.openOnFocus && !query && isPanelOpen || isPanelOpen);
965
+ var highlightedItem = getActiveItem(store.getState());
966
+
967
+ if (store.getState().activeItemId !== null && highlightedItem) {
968
+ var item = highlightedItem.item,
969
+ itemInputValue = highlightedItem.itemInputValue,
970
+ itemUrl = highlightedItem.itemUrl,
971
+ source = highlightedItem.source;
972
+ source.onActive(_objectSpread2({
973
+ event: event,
974
+ item: item,
975
+ itemInputValue: itemInputValue,
976
+ itemUrl: itemUrl,
977
+ refresh: refresh,
978
+ source: source,
979
+ state: store.getState()
980
+ }, setters));
981
+ }
982
+ }).finally(function () {
983
+ if (lastStalledId) {
984
+ props.environment.clearTimeout(lastStalledId);
985
+ }
771
986
  });
772
987
  }
773
988
 
989
+ var _excluded$1 = ["event", "props", "refresh", "store"];
774
990
  function onKeyDown(_ref) {
775
991
  var event = _ref.event,
776
992
  props = _ref.props,
777
993
  refresh = _ref.refresh,
778
994
  store = _ref.store,
779
- setters = _objectWithoutProperties(_ref, ["event", "props", "refresh", "store"]);
995
+ setters = _objectWithoutProperties(_ref, _excluded$1);
780
996
 
781
997
  if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
782
998
  // eslint-disable-next-line no-inner-declarations
@@ -942,17 +1158,22 @@
942
1158
  }
943
1159
  }
944
1160
 
1161
+ var _excluded$2 = ["props", "refresh", "store"],
1162
+ _excluded2 = ["inputElement", "formElement", "panelElement"],
1163
+ _excluded3 = ["inputElement"],
1164
+ _excluded4 = ["inputElement", "maxLength"],
1165
+ _excluded5 = ["item", "source"];
945
1166
  function getPropGetters(_ref) {
946
1167
  var props = _ref.props,
947
1168
  refresh = _ref.refresh,
948
1169
  store = _ref.store,
949
- setters = _objectWithoutProperties(_ref, ["props", "refresh", "store"]);
1170
+ setters = _objectWithoutProperties(_ref, _excluded$2);
950
1171
 
951
1172
  var getEnvironmentProps = function getEnvironmentProps(providedProps) {
952
1173
  var inputElement = providedProps.inputElement,
953
1174
  formElement = providedProps.formElement,
954
1175
  panelElement = providedProps.panelElement,
955
- rest = _objectWithoutProperties(providedProps, ["inputElement", "formElement", "panelElement"]);
1176
+ rest = _objectWithoutProperties(providedProps, _excluded2);
956
1177
 
957
1178
  return _objectSpread2({
958
1179
  // On touch devices, we do not rely on the native `blur` event of the
@@ -960,15 +1181,15 @@
960
1181
  // outside of the autocomplete elements.
961
1182
  // This ensures a working experience on mobile because we blur the input
962
1183
  // on touch devices when the user starts scrolling (`touchmove`).
1184
+ // @TODO: support cases where there are multiple Autocomplete instances.
1185
+ // Right now, a second instance makes this computation return false.
963
1186
  onTouchStart: function onTouchStart(event) {
964
1187
  if (store.getState().isOpen === false || event.target === inputElement) {
965
1188
  return;
966
- } // @TODO: support cases where there are multiple Autocomplete instances.
967
- // Right now, a second instance makes this computation return false.
968
-
1189
+ }
969
1190
 
970
1191
  var isTargetWithinAutocomplete = [formElement, panelElement].some(function (contextNode) {
971
- return isOrContainsNode(contextNode, event.target) || isOrContainsNode(contextNode, props.environment.document.activeElement);
1192
+ return isOrContainsNode(contextNode, event.target);
972
1193
  });
973
1194
 
974
1195
  if (isTargetWithinAutocomplete === false) {
@@ -1001,7 +1222,7 @@
1001
1222
 
1002
1223
  var getFormProps = function getFormProps(providedProps) {
1003
1224
  var inputElement = providedProps.inputElement,
1004
- rest = _objectWithoutProperties(providedProps, ["inputElement"]);
1225
+ rest = _objectWithoutProperties(providedProps, _excluded3);
1005
1226
 
1006
1227
  return _objectSpread2({
1007
1228
  action: '',
@@ -1057,7 +1278,7 @@
1057
1278
  inputElement = _ref2.inputElement,
1058
1279
  _ref2$maxLength = _ref2.maxLength,
1059
1280
  maxLength = _ref2$maxLength === void 0 ? 512 : _ref2$maxLength,
1060
- rest = _objectWithoutProperties(_ref2, ["inputElement", "maxLength"]);
1281
+ rest = _objectWithoutProperties(_ref2, _excluded4);
1061
1282
 
1062
1283
  var activeItem = getActiveItem(store.getState());
1063
1284
  return _objectSpread2({
@@ -1148,7 +1369,7 @@
1148
1369
  var getItemProps = function getItemProps(providedProps) {
1149
1370
  var item = providedProps.item,
1150
1371
  source = providedProps.source,
1151
- rest = _objectWithoutProperties(providedProps, ["item", "source"]);
1372
+ rest = _objectWithoutProperties(providedProps, _excluded5);
1152
1373
 
1153
1374
  return _objectSpread2({
1154
1375
  id: "".concat(props.id, "-item-").concat(item.__autocomplete_id),
@@ -1235,6 +1456,44 @@
1235
1456
  };
1236
1457
  }
1237
1458
 
1459
+ function getMetadata(_ref) {
1460
+ var _, _options$__autocomple, _options$__autocomple2, _options$__autocomple3;
1461
+
1462
+ var plugins = _ref.plugins,
1463
+ options = _ref.options;
1464
+ var optionsKey = (_ = (((_options$__autocomple = options.__autocomplete_metadata) === null || _options$__autocomple === void 0 ? void 0 : _options$__autocomple.userAgents) || [])[0]) === null || _ === void 0 ? void 0 : _.segment;
1465
+ var extraOptions = optionsKey ? _defineProperty({}, optionsKey, Object.keys(((_options$__autocomple2 = options.__autocomplete_metadata) === null || _options$__autocomple2 === void 0 ? void 0 : _options$__autocomple2.options) || {})) : {};
1466
+ return {
1467
+ plugins: plugins.map(function (plugin) {
1468
+ return {
1469
+ name: plugin.name,
1470
+ options: Object.keys(plugin.__autocomplete_pluginOptions || [])
1471
+ };
1472
+ }),
1473
+ options: _objectSpread2({
1474
+ 'autocomplete-core': Object.keys(options)
1475
+ }, extraOptions),
1476
+ ua: userAgents.concat(((_options$__autocomple3 = options.__autocomplete_metadata) === null || _options$__autocomple3 === void 0 ? void 0 : _options$__autocomple3.userAgents) || [])
1477
+ };
1478
+ }
1479
+ function injectMetadata(_ref3) {
1480
+ var _environment$navigato;
1481
+
1482
+ var metadata = _ref3.metadata,
1483
+ environment = _ref3.environment;
1484
+ var isMetadataEnabled = (_environment$navigato = environment.navigator) === null || _environment$navigato === void 0 ? void 0 : _environment$navigato.userAgent.includes('Algolia Crawler');
1485
+
1486
+ if (isMetadataEnabled) {
1487
+ var metadataContainer = environment.document.createElement('meta');
1488
+ var headRef = environment.document.querySelector('head');
1489
+ metadataContainer.name = 'algolia:metadata';
1490
+ setTimeout(function () {
1491
+ metadataContainer.content = JSON.stringify(metadata);
1492
+ headRef.appendChild(metadataContainer);
1493
+ }, 0);
1494
+ }
1495
+ }
1496
+
1238
1497
  function getCompletion(_ref) {
1239
1498
  var _getActiveItem;
1240
1499
 
@@ -1454,16 +1713,20 @@
1454
1713
  }
1455
1714
  }));
1456
1715
  });
1716
+ injectMetadata({
1717
+ metadata: getMetadata({
1718
+ plugins: props.plugins,
1719
+ options: options
1720
+ }),
1721
+ environment: props.environment
1722
+ });
1457
1723
  return _objectSpread2(_objectSpread2({
1458
1724
  refresh: refresh
1459
1725
  }, propGetters), setters);
1460
1726
  }
1461
1727
 
1462
- var version = '1.2.2';
1463
-
1464
1728
  exports.createAutocomplete = createAutocomplete;
1465
1729
  exports.getDefaultProps = getDefaultProps;
1466
- exports.version = version;
1467
1730
 
1468
1731
  Object.defineProperty(exports, '__esModule', { value: true });
1469
1732