@algolia/autocomplete-core 1.5.1 → 1.5.4

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.
@@ -1,4 +1,4 @@
1
- /*! @algolia/autocomplete-core 1.5.1 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
1
+ /*! @algolia/autocomplete-core 1.5.4 | 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) :
@@ -10,14 +10,9 @@
10
10
 
11
11
  if (Object.getOwnPropertySymbols) {
12
12
  var symbols = Object.getOwnPropertySymbols(object);
13
-
14
- if (enumerableOnly) {
15
- symbols = symbols.filter(function (sym) {
16
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
17
- });
18
- }
19
-
20
- keys.push.apply(keys, symbols);
13
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
14
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
15
+ })), keys.push.apply(keys, symbols);
21
16
  }
22
17
 
23
18
  return keys;
@@ -25,19 +20,12 @@
25
20
 
26
21
  function _objectSpread2(target) {
27
22
  for (var i = 1; i < arguments.length; i++) {
28
- var source = arguments[i] != null ? arguments[i] : {};
29
-
30
- if (i % 2) {
31
- ownKeys(Object(source), true).forEach(function (key) {
32
- _defineProperty(target, key, source[key]);
33
- });
34
- } else if (Object.getOwnPropertyDescriptors) {
35
- Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
36
- } else {
37
- ownKeys(Object(source)).forEach(function (key) {
38
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
39
- });
40
- }
23
+ var source = null != arguments[i] ? arguments[i] : {};
24
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
25
+ _defineProperty(target, key, source[key]);
26
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
27
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
28
+ });
41
29
  }
42
30
 
43
31
  return target;
@@ -46,17 +34,11 @@
46
34
  function _typeof$1(obj) {
47
35
  "@babel/helpers - typeof";
48
36
 
49
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
50
- _typeof$1 = function (obj) {
51
- return typeof obj;
52
- };
53
- } else {
54
- _typeof$1 = function (obj) {
55
- return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
56
- };
57
- }
58
-
59
- return _typeof$1(obj);
37
+ return _typeof$1 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
38
+ return typeof obj;
39
+ } : function (obj) {
40
+ return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
41
+ }, _typeof$1(obj);
60
42
  }
61
43
 
62
44
  function _defineProperty(obj, key, value) {
@@ -207,17 +189,11 @@
207
189
  function _typeof(obj) {
208
190
  "@babel/helpers - typeof";
209
191
 
210
- if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
211
- _typeof = function _typeof(obj) {
212
- return typeof obj;
213
- };
214
- } else {
215
- _typeof = function _typeof(obj) {
216
- return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
217
- };
218
- }
219
-
220
- return _typeof(obj);
192
+ return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) {
193
+ return typeof obj;
194
+ } : function (obj) {
195
+ return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
196
+ }, _typeof(obj);
221
197
  }
222
198
  /**
223
199
  * Decycles objects with circular references.
@@ -288,7 +264,7 @@
288
264
 
289
265
  var noop = function noop() {};
290
266
 
291
- var version = '1.5.1';
267
+ var version = '1.5.4';
292
268
 
293
269
  var userAgents = [{
294
270
  segment: 'autocomplete-core',
@@ -323,75 +299,79 @@
323
299
  "development" !== 'production' ? warn(!options.debug, 'The `debug` option is meant for development debugging and should not be used in production.') : void 0;
324
300
  }
325
301
 
326
- function createStore(reducer, props, onStoreStateChange) {
327
- var state = props.initialState;
302
+ function createInternalCancelablePromise(promise, initialState) {
303
+ var state = initialState;
328
304
  return {
329
- getState: function getState() {
330
- return state;
305
+ then: function then(onfulfilled, onrejected) {
306
+ return createInternalCancelablePromise(promise.then(createCallback(onfulfilled, state, promise), createCallback(onrejected, state, promise)), state);
331
307
  },
332
- dispatch: function dispatch(action, payload) {
333
- var prevState = _objectSpread2({}, state);
308
+ catch: function _catch(onrejected) {
309
+ return createInternalCancelablePromise(promise.catch(createCallback(onrejected, state, promise)), state);
310
+ },
311
+ finally: function _finally(onfinally) {
312
+ if (onfinally) {
313
+ state.onCancelList.push(onfinally);
314
+ }
334
315
 
335
- state = reducer(state, {
336
- type: action,
337
- props: props,
338
- payload: payload
339
- });
340
- onStoreStateChange({
341
- state: state,
342
- prevState: prevState
316
+ return createInternalCancelablePromise(promise.finally(createCallback(onfinally && function () {
317
+ state.onCancelList = [];
318
+ return onfinally();
319
+ }, state, promise)), state);
320
+ },
321
+ cancel: function cancel() {
322
+ state.isCanceled = true;
323
+ var callbacks = state.onCancelList;
324
+ state.onCancelList = [];
325
+ callbacks.forEach(function (callback) {
326
+ callback();
343
327
  });
344
328
  },
345
- shouldSkipPendingUpdate: false
329
+ isCanceled: function isCanceled() {
330
+ return state.isCanceled === true;
331
+ }
346
332
  };
347
333
  }
348
334
 
349
- function getAutocompleteSetters(_ref) {
350
- var store = _ref.store;
351
-
352
- var setActiveItemId = function setActiveItemId(value) {
353
- store.dispatch('setActiveItemId', value);
354
- };
355
-
356
- var setQuery = function setQuery(value) {
357
- store.dispatch('setQuery', value);
358
- };
359
-
360
- var setCollections = function setCollections(rawValue) {
361
- var baseItemId = 0;
362
- var value = rawValue.map(function (collection) {
363
- return _objectSpread2(_objectSpread2({}, collection), {}, {
364
- // We flatten the stored items to support calling `getAlgoliaResults`
365
- // from the source itself.
366
- items: flatten(collection.items).map(function (item) {
367
- return _objectSpread2(_objectSpread2({}, item), {}, {
368
- __autocomplete_id: baseItemId++
369
- });
370
- })
371
- });
372
- });
373
- store.dispatch('setCollections', value);
374
- };
335
+ function cancelable(promise) {
336
+ return createInternalCancelablePromise(promise, {
337
+ isCanceled: false,
338
+ onCancelList: []
339
+ });
340
+ }
375
341
 
376
- var setIsOpen = function setIsOpen(value) {
377
- store.dispatch('setIsOpen', value);
378
- };
342
+ function createCallback(onResult, state, fallback) {
343
+ if (!onResult) {
344
+ return fallback;
345
+ }
379
346
 
380
- var setStatus = function setStatus(value) {
381
- store.dispatch('setStatus', value);
382
- };
347
+ return function callback(arg) {
348
+ if (state.isCanceled) {
349
+ return arg;
350
+ }
383
351
 
384
- var setContext = function setContext(value) {
385
- store.dispatch('setContext', value);
352
+ return onResult(arg);
386
353
  };
354
+ }
387
355
 
356
+ function createCancelablePromiseList() {
357
+ var list = [];
388
358
  return {
389
- setActiveItemId: setActiveItemId,
390
- setQuery: setQuery,
391
- setCollections: setCollections,
392
- setIsOpen: setIsOpen,
393
- setStatus: setStatus,
394
- setContext: setContext
359
+ add: function add(cancelablePromise) {
360
+ list.push(cancelablePromise);
361
+ return cancelablePromise.finally(function () {
362
+ list = list.filter(function (item) {
363
+ return item !== cancelablePromise;
364
+ });
365
+ });
366
+ },
367
+ cancelAll: function cancelAll() {
368
+ list.forEach(function (promise) {
369
+ return promise.cancel();
370
+ });
371
+ },
372
+ isEmpty: function isEmpty() {
373
+ return list.length === 0;
374
+ }
395
375
  };
396
376
  }
397
377
 
@@ -405,11 +385,8 @@
405
385
  var basePromiseId = -1;
406
386
  var latestResolvedId = -1;
407
387
  var latestResolvedValue = undefined;
408
- var runningPromisesCount = 0;
409
-
410
- function runConcurrentSafePromise(promise) {
388
+ return function runConcurrentSafePromise(promise) {
411
389
  basePromiseId++;
412
- runningPromisesCount++;
413
390
  var currentPromiseId = basePromiseId;
414
391
  return Promise.resolve(promise).then(function (x) {
415
392
  // The promise might take too long to resolve and get outdated. This would
@@ -432,16 +409,8 @@
432
409
  latestResolvedId = currentPromiseId;
433
410
  latestResolvedValue = x;
434
411
  return x;
435
- }).finally(function () {
436
- return runningPromisesCount--;
437
412
  });
438
- }
439
-
440
- runConcurrentSafePromise.isRunning = function () {
441
- return runningPromisesCount > 0;
442
413
  };
443
-
444
- return runConcurrentSafePromise;
445
414
  }
446
415
 
447
416
  /**
@@ -646,6 +615,78 @@
646
615
  };
647
616
  }
648
617
 
618
+ function createStore(reducer, props, onStoreStateChange) {
619
+ var state = props.initialState;
620
+ return {
621
+ getState: function getState() {
622
+ return state;
623
+ },
624
+ dispatch: function dispatch(action, payload) {
625
+ var prevState = _objectSpread2({}, state);
626
+
627
+ state = reducer(state, {
628
+ type: action,
629
+ props: props,
630
+ payload: payload
631
+ });
632
+ onStoreStateChange({
633
+ state: state,
634
+ prevState: prevState
635
+ });
636
+ },
637
+ pendingRequests: createCancelablePromiseList()
638
+ };
639
+ }
640
+
641
+ function getAutocompleteSetters(_ref) {
642
+ var store = _ref.store;
643
+
644
+ var setActiveItemId = function setActiveItemId(value) {
645
+ store.dispatch('setActiveItemId', value);
646
+ };
647
+
648
+ var setQuery = function setQuery(value) {
649
+ store.dispatch('setQuery', value);
650
+ };
651
+
652
+ var setCollections = function setCollections(rawValue) {
653
+ var baseItemId = 0;
654
+ var value = rawValue.map(function (collection) {
655
+ return _objectSpread2(_objectSpread2({}, collection), {}, {
656
+ // We flatten the stored items to support calling `getAlgoliaResults`
657
+ // from the source itself.
658
+ items: flatten(collection.items).map(function (item) {
659
+ return _objectSpread2(_objectSpread2({}, item), {}, {
660
+ __autocomplete_id: baseItemId++
661
+ });
662
+ })
663
+ });
664
+ });
665
+ store.dispatch('setCollections', value);
666
+ };
667
+
668
+ var setIsOpen = function setIsOpen(value) {
669
+ store.dispatch('setIsOpen', value);
670
+ };
671
+
672
+ var setStatus = function setStatus(value) {
673
+ store.dispatch('setStatus', value);
674
+ };
675
+
676
+ var setContext = function setContext(value) {
677
+ store.dispatch('setContext', value);
678
+ };
679
+
680
+ return {
681
+ setActiveItemId: setActiveItemId,
682
+ setQuery: setQuery,
683
+ setCollections: setCollections,
684
+ setIsOpen: setIsOpen,
685
+ setStatus: setStatus,
686
+ setContext: setContext
687
+ };
688
+ }
689
+
649
690
  function getDefaultProps(props, pluginSubscribers) {
650
691
  var _props$id;
651
692
 
@@ -826,9 +867,10 @@
826
867
 
827
868
  var searchClient = current.searchClient,
828
869
  execute = current.execute,
870
+ requesterId = current.requesterId,
829
871
  requests = current.requests;
830
872
  var container = acc.find(function (item) {
831
- return isDescription(current) && isDescription(item) && item.searchClient === searchClient && item.execute === execute;
873
+ return isDescription(current) && isDescription(item) && item.searchClient === searchClient && Boolean(requesterId) && item.requesterId === requesterId;
832
874
  });
833
875
 
834
876
  if (container) {
@@ -838,6 +880,7 @@
838
880
  } else {
839
881
  var request = {
840
882
  execute: execute,
883
+ requesterId: requesterId,
841
884
  items: requests,
842
885
  searchClient: searchClient
843
886
  };
@@ -928,9 +971,11 @@
928
971
  // updates performed in this code path.
929
972
  // We chain with a void promise to respect `onInput`'s expected return type.
930
973
 
931
- return runConcurrentSafePromise(collections).then(function () {
974
+ var _request = cancelable(runConcurrentSafePromise(collections).then(function () {
932
975
  return Promise.resolve();
933
- });
976
+ }));
977
+
978
+ return store.pendingRequests.add(_request);
934
979
  }
935
980
 
936
981
  setStatus('loading');
@@ -943,7 +988,7 @@
943
988
  // meaning we should only ever manipulate the state once this concurrent-safe
944
989
  // promise is resolved.
945
990
 
946
- return runConcurrentSafePromise(props.getSources(_objectSpread2({
991
+ var request = cancelable(runConcurrentSafePromise(props.getSources(_objectSpread2({
947
992
  query: query,
948
993
  refresh: refresh,
949
994
  state: store.getState()
@@ -965,7 +1010,7 @@
965
1010
  state: store.getState()
966
1011
  });
967
1012
  });
968
- })).then(function (collections) {
1013
+ }))).then(function (collections) {
969
1014
  var _nextState$isOpen2;
970
1015
 
971
1016
  // Parameters passed to `onInput` could be stale when the following code
@@ -973,15 +1018,6 @@
973
1018
  // If it becomes a problem we'll need to save the last passed parameters.
974
1019
  // See: https://codesandbox.io/s/agitated-cookies-y290z
975
1020
  setStatus('idle');
976
-
977
- if (store.shouldSkipPendingUpdate) {
978
- if (!runConcurrentSafePromise.isRunning()) {
979
- store.shouldSkipPendingUpdate = false;
980
- }
981
-
982
- return;
983
- }
984
-
985
1021
  setCollections(collections);
986
1022
  var isPanelOpen = props.shouldPanelOpen({
987
1023
  state: store.getState()
@@ -1005,12 +1041,14 @@
1005
1041
  }, setters));
1006
1042
  }
1007
1043
  }).finally(function () {
1044
+ setStatus('idle');
1045
+
1008
1046
  if (lastStalledId) {
1009
1047
  props.environment.clearTimeout(lastStalledId);
1010
1048
  }
1011
1049
  });
1050
+ return store.pendingRequests.add(request);
1012
1051
  }
1013
- onInput.isRunning = runConcurrentSafePromise.isRunning;
1014
1052
 
1015
1053
  var _excluded$1 = ["event", "props", "refresh", "store"];
1016
1054
  function onKeyDown(_ref) {
@@ -1089,12 +1127,10 @@
1089
1127
  event.preventDefault();
1090
1128
  store.dispatch(event.key, null); // Hitting the `Escape` key signals the end of a user interaction with the
1091
1129
  // autocomplete. At this point, we should ignore any requests that are still
1092
- // running and could reopen the panel once they resolve, because that would
1130
+ // pending and could reopen the panel once they resolve, because that would
1093
1131
  // result in an unsolicited UI behavior.
1094
1132
 
1095
- if (onInput.isRunning()) {
1096
- store.shouldSkipPendingUpdate = true;
1097
- }
1133
+ store.pendingRequests.cancelAll();
1098
1134
  } else if (event.key === 'Enter') {
1099
1135
  // No active item, so we let the browser handle the native `onSubmit` form
1100
1136
  // event.
@@ -1220,12 +1256,12 @@
1220
1256
  // The `onTouchStart` event shouldn't trigger the `blur` handler when
1221
1257
  // it's not an interaction with Autocomplete. We detect it with the
1222
1258
  // following heuristics:
1223
- // - the panel is closed AND there are no running requests
1259
+ // - the panel is closed AND there are no pending requests
1224
1260
  // (no interaction with the autocomplete, no future state updates)
1225
1261
  // - OR the touched target is the input element (should open the panel)
1226
- var isNotAutocompleteInteraction = store.getState().isOpen === false && !onInput.isRunning();
1262
+ var isAutocompleteInteraction = store.getState().isOpen || !store.pendingRequests.isEmpty();
1227
1263
 
1228
- if (isNotAutocompleteInteraction || event.target === inputElement) {
1264
+ if (!isAutocompleteInteraction || event.target === inputElement) {
1229
1265
  return;
1230
1266
  }
1231
1267
 
@@ -1234,13 +1270,13 @@
1234
1270
  });
1235
1271
 
1236
1272
  if (isTargetWithinAutocomplete === false) {
1237
- store.dispatch('blur', null); // If requests are still running when the user closes the panel, they
1273
+ store.dispatch('blur', null); // If requests are still pending when the user closes the panel, they
1238
1274
  // could reopen the panel once they resolve.
1239
1275
  // We want to prevent any subsequent query from reopening the panel
1240
1276
  // because it would result in an unsolicited UI behavior.
1241
1277
 
1242
- if (!props.debug && onInput.isRunning()) {
1243
- store.shouldSkipPendingUpdate = true;
1278
+ if (!props.debug) {
1279
+ store.pendingRequests.cancelAll();
1244
1280
  }
1245
1281
  }
1246
1282
  },
@@ -1367,13 +1403,13 @@
1367
1403
  // We do rely on the `blur` event on touch devices.
1368
1404
  // See explanation in `onTouchStart`.
1369
1405
  if (!isTouchDevice) {
1370
- store.dispatch('blur', null); // If requests are still running when the user closes the panel, they
1406
+ store.dispatch('blur', null); // If requests are still pending when the user closes the panel, they
1371
1407
  // could reopen the panel once they resolve.
1372
1408
  // We want to prevent any subsequent query from reopening the panel
1373
1409
  // because it would result in an unsolicited UI behavior.
1374
1410
 
1375
- if (!props.debug && onInput.isRunning()) {
1376
- store.shouldSkipPendingUpdate = true;
1411
+ if (!props.debug) {
1412
+ store.pendingRequests.cancelAll();
1377
1413
  }
1378
1414
  }
1379
1415
  },