@algolia/autocomplete-core 1.4.0 → 1.5.2

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 (49) 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 +4 -2
  4. package/dist/esm/getAutocompleteSetters.js +1 -1
  5. package/dist/esm/getDefaultProps.js +2 -2
  6. package/dist/esm/getPropGetters.js +41 -13
  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.d.ts +2 -1
  12. package/dist/esm/onInput.js +63 -39
  13. package/dist/esm/onKeyDown.js +10 -3
  14. package/dist/esm/reshape.js +1 -1
  15. package/dist/esm/resolve.js +2 -2
  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.js +1 -0
  24. package/dist/esm/types/AutocompletePlugin.d.ts +10 -0
  25. package/dist/esm/types/AutocompletePlugin.js +1 -0
  26. package/dist/esm/types/AutocompletePropGetters.js +1 -0
  27. package/dist/esm/types/AutocompleteReshape.js +1 -0
  28. package/dist/esm/types/AutocompleteSetters.js +1 -0
  29. package/dist/esm/types/AutocompleteSource.js +1 -0
  30. package/dist/esm/types/AutocompleteState.js +1 -0
  31. package/dist/esm/types/AutocompleteStore.d.ts +2 -0
  32. package/dist/esm/types/AutocompleteStore.js +1 -0
  33. package/dist/esm/types/AutocompleteSubscribers.js +1 -0
  34. package/dist/esm/utils/createCancelablePromise.d.ts +15 -0
  35. package/dist/esm/utils/createCancelablePromise.js +70 -0
  36. package/dist/esm/utils/createCancelablePromiseList.d.ts +7 -0
  37. package/dist/esm/utils/createCancelablePromiseList.js +21 -0
  38. package/dist/esm/utils/createConcurrentSafePromise.d.ts +1 -1
  39. package/dist/esm/utils/getNormalizedSources.js +1 -1
  40. package/dist/esm/utils/index.d.ts +2 -0
  41. package/dist/esm/utils/index.js +2 -0
  42. package/dist/esm/utils/mapToAlgoliaResponse.js +1 -1
  43. package/dist/umd/index.development.js +396 -169
  44. package/dist/umd/index.development.js.map +1 -1
  45. package/dist/umd/index.production.js +2 -2
  46. package/dist/umd/index.production.js.map +1 -1
  47. package/package.json +3 -3
  48. package/dist/esm/version.d.ts +0 -1
  49. package/dist/esm/version.js +0 -1
@@ -1,2 +1,8 @@
1
- import { AutocompleteApi, AutocompleteOptions, BaseItem } from './types';
2
- export declare function createAutocomplete<TItem extends BaseItem, TEvent = Event, TMouseEvent = MouseEvent, TKeyboardEvent = KeyboardEvent>(options: AutocompleteOptions<TItem>): AutocompleteApi<TItem, TEvent, TMouseEvent, TKeyboardEvent>;
1
+ import { AutocompleteApi, AutocompleteOptions as AutocompleteCoreOptions, BaseItem } from './types';
2
+ export interface AutocompleteOptionsWithMetadata<TItem extends BaseItem> extends AutocompleteCoreOptions<TItem> {
3
+ /**
4
+ * @internal
5
+ */
6
+ __autocomplete_metadata?: Record<string, unknown>;
7
+ }
8
+ export declare function createAutocomplete<TItem extends BaseItem, TEvent = Event, TMouseEvent = MouseEvent, TKeyboardEvent = KeyboardEvent>(options: AutocompleteOptionsWithMetadata<TItem>): AutocompleteApi<TItem, TEvent, TMouseEvent, TKeyboardEvent>;
@@ -1,4 +1,4 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
2
 
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
4
 
@@ -9,6 +9,7 @@ import { createStore } from './createStore';
9
9
  import { getAutocompleteSetters } from './getAutocompleteSetters';
10
10
  import { getDefaultProps } from './getDefaultProps';
11
11
  import { getPropGetters } from './getPropGetters';
12
+ import { getMetadata, injectMetadata } from './metadata';
12
13
  import { onInput } from './onInput';
13
14
  import { stateReducer } from './stateReducer';
14
15
  export function createAutocomplete(options) {
@@ -65,6 +66,13 @@ export function createAutocomplete(options) {
65
66
  }
66
67
  }));
67
68
  });
69
+ injectMetadata({
70
+ metadata: getMetadata({
71
+ plugins: props.plugins,
72
+ options: options
73
+ }),
74
+ environment: props.environment
75
+ });
68
76
  return _objectSpread(_objectSpread({
69
77
  refresh: refresh
70
78
  }, propGetters), setters);
@@ -1,9 +1,10 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
2
 
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
4
 
5
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
6
 
7
+ import { createCancelablePromiseList } from './utils';
7
8
  export function createStore(reducer, props, onStoreStateChange) {
8
9
  var state = props.initialState;
9
10
  return {
@@ -22,6 +23,7 @@ export function createStore(reducer, props, onStoreStateChange) {
22
23
  state: state,
23
24
  prevState: prevState
24
25
  });
25
- }
26
+ },
27
+ pendingRequests: createCancelablePromiseList()
26
28
  };
27
29
  }
@@ -1,4 +1,4 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
2
 
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
4
 
@@ -4,13 +4,13 @@ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread n
4
4
 
5
5
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
6
6
 
7
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
7
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
8
8
 
9
9
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
10
10
 
11
11
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
12
12
 
13
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
13
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
14
14
 
15
15
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
16
16
 
@@ -1,4 +1,10 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ var _excluded = ["props", "refresh", "store"],
2
+ _excluded2 = ["inputElement", "formElement", "panelElement"],
3
+ _excluded3 = ["inputElement"],
4
+ _excluded4 = ["inputElement", "maxLength"],
5
+ _excluded5 = ["item", "source"];
6
+
7
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
8
 
3
9
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
10
 
@@ -15,13 +21,13 @@ export function getPropGetters(_ref) {
15
21
  var props = _ref.props,
16
22
  refresh = _ref.refresh,
17
23
  store = _ref.store,
18
- setters = _objectWithoutProperties(_ref, ["props", "refresh", "store"]);
24
+ setters = _objectWithoutProperties(_ref, _excluded);
19
25
 
20
26
  var getEnvironmentProps = function getEnvironmentProps(providedProps) {
21
27
  var inputElement = providedProps.inputElement,
22
28
  formElement = providedProps.formElement,
23
29
  panelElement = providedProps.panelElement,
24
- rest = _objectWithoutProperties(providedProps, ["inputElement", "formElement", "panelElement"]);
30
+ rest = _objectWithoutProperties(providedProps, _excluded2);
25
31
 
26
32
  return _objectSpread({
27
33
  // On touch devices, we do not rely on the native `blur` event of the
@@ -29,19 +35,34 @@ export function getPropGetters(_ref) {
29
35
  // outside of the autocomplete elements.
30
36
  // This ensures a working experience on mobile because we blur the input
31
37
  // on touch devices when the user starts scrolling (`touchmove`).
38
+ // @TODO: support cases where there are multiple Autocomplete instances.
39
+ // Right now, a second instance makes this computation return false.
32
40
  onTouchStart: function onTouchStart(event) {
33
- if (store.getState().isOpen === false || event.target === inputElement) {
34
- return;
35
- } // @TODO: support cases where there are multiple Autocomplete instances.
36
- // Right now, a second instance makes this computation return false.
41
+ // The `onTouchStart` event shouldn't trigger the `blur` handler when
42
+ // it's not an interaction with Autocomplete. We detect it with the
43
+ // following heuristics:
44
+ // - the panel is closed AND there are no pending requests
45
+ // (no interaction with the autocomplete, no future state updates)
46
+ // - OR the touched target is the input element (should open the panel)
47
+ var isAutocompleteInteraction = store.getState().isOpen || !store.pendingRequests.isEmpty();
37
48
 
49
+ if (!isAutocompleteInteraction || event.target === inputElement) {
50
+ return;
51
+ }
38
52
 
39
53
  var isTargetWithinAutocomplete = [formElement, panelElement].some(function (contextNode) {
40
- return isOrContainsNode(contextNode, event.target) || isOrContainsNode(contextNode, props.environment.document.activeElement);
54
+ return isOrContainsNode(contextNode, event.target);
41
55
  });
42
56
 
43
57
  if (isTargetWithinAutocomplete === false) {
44
- store.dispatch('blur', null);
58
+ store.dispatch('blur', null); // If requests are still pending when the user closes the panel, they
59
+ // could reopen the panel once they resolve.
60
+ // We want to prevent any subsequent query from reopening the panel
61
+ // because it would result in an unsolicited UI behavior.
62
+
63
+ if (!props.debug) {
64
+ store.pendingRequests.cancelAll();
65
+ }
45
66
  }
46
67
  },
47
68
  // When scrolling on touch devices (mobiles, tablets, etc.), we want to
@@ -70,7 +91,7 @@ export function getPropGetters(_ref) {
70
91
 
71
92
  var getFormProps = function getFormProps(providedProps) {
72
93
  var inputElement = providedProps.inputElement,
73
- rest = _objectWithoutProperties(providedProps, ["inputElement"]);
94
+ rest = _objectWithoutProperties(providedProps, _excluded3);
74
95
 
75
96
  return _objectSpread({
76
97
  action: '',
@@ -126,7 +147,7 @@ export function getPropGetters(_ref) {
126
147
  inputElement = _ref2.inputElement,
127
148
  _ref2$maxLength = _ref2.maxLength,
128
149
  maxLength = _ref2$maxLength === void 0 ? 512 : _ref2$maxLength,
129
- rest = _objectWithoutProperties(_ref2, ["inputElement", "maxLength"]);
150
+ rest = _objectWithoutProperties(_ref2, _excluded4);
130
151
 
131
152
  var activeItem = getActiveItem(store.getState());
132
153
  return _objectSpread({
@@ -167,7 +188,14 @@ export function getPropGetters(_ref) {
167
188
  // We do rely on the `blur` event on touch devices.
168
189
  // See explanation in `onTouchStart`.
169
190
  if (!isTouchDevice) {
170
- store.dispatch('blur', null);
191
+ store.dispatch('blur', null); // If requests are still pending when the user closes the panel, they
192
+ // could reopen the panel once they resolve.
193
+ // We want to prevent any subsequent query from reopening the panel
194
+ // because it would result in an unsolicited UI behavior.
195
+
196
+ if (!props.debug) {
197
+ store.pendingRequests.cancelAll();
198
+ }
171
199
  }
172
200
  },
173
201
  onClick: function onClick(event) {
@@ -217,7 +245,7 @@ export function getPropGetters(_ref) {
217
245
  var getItemProps = function getItemProps(providedProps) {
218
246
  var item = providedProps.item,
219
247
  source = providedProps.source,
220
- rest = _objectWithoutProperties(providedProps, ["item", "source"]);
248
+ rest = _objectWithoutProperties(providedProps, _excluded5);
221
249
 
222
250
  return _objectSpread({
223
251
  id: "".concat(props.id, "-item-").concat(item.__autocomplete_id),
@@ -1,4 +1,3 @@
1
1
  export * from './createAutocomplete';
2
2
  export * from './getDefaultProps';
3
3
  export * from './types';
4
- export * from './version';
package/dist/esm/index.js CHANGED
@@ -1,4 +1,3 @@
1
1
  export * from './createAutocomplete';
2
2
  export * from './getDefaultProps';
3
- export * from './types';
4
- export * from './version';
3
+ export * from './types';
@@ -0,0 +1,33 @@
1
+ import { UserAgent } from '@algolia/autocomplete-shared';
2
+ import { AutocompleteEnvironment, AutocompleteOptionsWithMetadata, AutocompletePlugin, BaseItem } from '.';
3
+ declare type AutocompleteMetadata = {
4
+ plugins: Array<{
5
+ name: string | undefined;
6
+ options: string[];
7
+ }>;
8
+ options: Record<string, string[]>;
9
+ ua: UserAgent[];
10
+ };
11
+ declare type GetMetadataParams<TItem extends BaseItem, TData = unknown> = {
12
+ plugins: Array<AutocompletePlugin<TItem, TData>>;
13
+ options: AutocompleteOptionsWithMetadata<TItem>;
14
+ };
15
+ export declare function getMetadata<TItem extends BaseItem, TData = unknown>({ plugins, options, }: GetMetadataParams<TItem, TData>): {
16
+ plugins: {
17
+ name: string | undefined;
18
+ options: string[];
19
+ }[];
20
+ options: {
21
+ 'autocomplete-core': string[];
22
+ };
23
+ ua: {
24
+ segment: string;
25
+ version: string;
26
+ }[];
27
+ };
28
+ declare type InlineMetadataParams = {
29
+ metadata: AutocompleteMetadata;
30
+ environment: AutocompleteEnvironment;
31
+ };
32
+ export declare function injectMetadata({ metadata, environment, }: InlineMetadataParams): void;
33
+ export {};
@@ -0,0 +1,44 @@
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
+
3
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
+
5
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
+
7
+ import { userAgents } from '@algolia/autocomplete-shared';
8
+ export function getMetadata(_ref) {
9
+ var _, _options$__autocomple, _options$__autocomple2, _options$__autocomple3;
10
+
11
+ var plugins = _ref.plugins,
12
+ options = _ref.options;
13
+ var optionsKey = (_ = (((_options$__autocomple = options.__autocomplete_metadata) === null || _options$__autocomple === void 0 ? void 0 : _options$__autocomple.userAgents) || [])[0]) === null || _ === void 0 ? void 0 : _.segment;
14
+ var extraOptions = optionsKey ? _defineProperty({}, optionsKey, Object.keys(((_options$__autocomple2 = options.__autocomplete_metadata) === null || _options$__autocomple2 === void 0 ? void 0 : _options$__autocomple2.options) || {})) : {};
15
+ return {
16
+ plugins: plugins.map(function (plugin) {
17
+ return {
18
+ name: plugin.name,
19
+ options: Object.keys(plugin.__autocomplete_pluginOptions || [])
20
+ };
21
+ }),
22
+ options: _objectSpread({
23
+ 'autocomplete-core': Object.keys(options)
24
+ }, extraOptions),
25
+ ua: userAgents.concat(((_options$__autocomple3 = options.__autocomplete_metadata) === null || _options$__autocomple3 === void 0 ? void 0 : _options$__autocomple3.userAgents) || [])
26
+ };
27
+ }
28
+ export function injectMetadata(_ref3) {
29
+ var _environment$navigato;
30
+
31
+ var metadata = _ref3.metadata,
32
+ environment = _ref3.environment;
33
+ var isMetadataEnabled = (_environment$navigato = environment.navigator) === null || _environment$navigato === void 0 ? void 0 : _environment$navigato.userAgent.includes('Algolia Crawler');
34
+
35
+ if (isMetadataEnabled) {
36
+ var metadataContainer = environment.document.createElement('meta');
37
+ var headRef = environment.document.querySelector('head');
38
+ metadataContainer.name = 'algolia:metadata';
39
+ setTimeout(function () {
40
+ metadataContainer.content = JSON.stringify(metadata);
41
+ headRef.appendChild(metadataContainer);
42
+ }, 0);
43
+ }
44
+ }
@@ -1,4 +1,5 @@
1
1
  import { AutocompleteScopeApi, AutocompleteState, AutocompleteStore, BaseItem, InternalAutocompleteOptions } from './types';
2
+ import { CancelablePromise } from './utils';
2
3
  interface OnInputParams<TItem extends BaseItem> extends AutocompleteScopeApi<TItem> {
3
4
  event: any;
4
5
  /**
@@ -13,5 +14,5 @@ interface OnInputParams<TItem extends BaseItem> extends AutocompleteScopeApi<TIt
13
14
  query: string;
14
15
  store: AutocompleteStore<TItem>;
15
16
  }
16
- export declare function onInput<TItem extends BaseItem>({ event, nextState, props, query, refresh, store, ...setters }: OnInputParams<TItem>): Promise<void>;
17
+ export declare function onInput<TItem extends BaseItem>({ event, nextState, props, query, refresh, store, ...setters }: OnInputParams<TItem>): CancelablePromise<void>;
17
18
  export {};
@@ -1,4 +1,6 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ var _excluded = ["event", "nextState", "props", "query", "refresh", "store"];
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
4
 
3
5
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
6
 
@@ -10,8 +12,9 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) r
10
12
 
11
13
  import { reshape } from './reshape';
12
14
  import { preResolve, resolve, postResolve } from './resolve';
13
- import { getActiveItem } from './utils';
15
+ import { cancelable, createConcurrentSafePromise, getActiveItem } from './utils';
14
16
  var lastStalledId = null;
17
+ var runConcurrentSafePromise = createConcurrentSafePromise();
15
18
  export function onInput(_ref) {
16
19
  var event = _ref.event,
17
20
  _ref$nextState = _ref.nextState,
@@ -20,7 +23,7 @@ export function onInput(_ref) {
20
23
  query = _ref.query,
21
24
  refresh = _ref.refresh,
22
25
  store = _ref.store,
23
- setters = _objectWithoutProperties(_ref, ["event", "nextState", "props", "query", "refresh", "store"]);
26
+ setters = _objectWithoutProperties(_ref, _excluded);
24
27
 
25
28
  if (lastStalledId) {
26
29
  props.environment.clearTimeout(lastStalledId);
@@ -37,28 +40,42 @@ export function onInput(_ref) {
37
40
  if (!query && props.openOnFocus === false) {
38
41
  var _nextState$isOpen;
39
42
 
40
- setStatus('idle');
41
- setCollections(store.getState().collections.map(function (collection) {
43
+ var collections = store.getState().collections.map(function (collection) {
42
44
  return _objectSpread(_objectSpread({}, collection), {}, {
43
45
  items: []
44
46
  });
45
- }));
47
+ });
48
+ setStatus('idle');
49
+ setCollections(collections);
46
50
  setIsOpen((_nextState$isOpen = nextState.isOpen) !== null && _nextState$isOpen !== void 0 ? _nextState$isOpen : props.shouldPanelOpen({
47
51
  state: store.getState()
52
+ })); // We make sure to update the latest resolved value of the tracked
53
+ // promises to keep late resolving promises from "cancelling" the state
54
+ // updates performed in this code path.
55
+ // We chain with a void promise to respect `onInput`'s expected return type.
56
+
57
+ var _request = cancelable(runConcurrentSafePromise(collections).then(function () {
58
+ return Promise.resolve();
48
59
  }));
49
- return Promise.resolve();
60
+
61
+ return store.pendingRequests.add(_request);
50
62
  }
51
63
 
52
64
  setStatus('loading');
53
65
  lastStalledId = props.environment.setTimeout(function () {
54
66
  setStatus('stalled');
55
- }, props.stallThreshold);
56
- return props.getSources(_objectSpread({
67
+ }, props.stallThreshold); // We track the entire promise chain triggered by `onInput` before mutating
68
+ // the Autocomplete state to make sure that any state manipulation is based on
69
+ // fresh data regardless of when promises individually resolve.
70
+ // We don't track nested promises and only rely on the full chain resolution,
71
+ // meaning we should only ever manipulate the state once this concurrent-safe
72
+ // promise is resolved.
73
+
74
+ var request = cancelable(runConcurrentSafePromise(props.getSources(_objectSpread({
57
75
  query: query,
58
76
  refresh: refresh,
59
77
  state: store.getState()
60
78
  }, setters)).then(function (sources) {
61
- setStatus('loading');
62
79
  return Promise.all(sources.map(function (source) {
63
80
  return Promise.resolve(source.getItems(_objectSpread({
64
81
  query: query,
@@ -75,36 +92,43 @@ export function onInput(_ref) {
75
92
  props: props,
76
93
  state: store.getState()
77
94
  });
78
- }).then(function (collections) {
79
- var _nextState$isOpen2;
95
+ });
96
+ }))).then(function (collections) {
97
+ var _nextState$isOpen2;
80
98
 
81
- setStatus('idle');
82
- setCollections(collections);
83
- var isPanelOpen = props.shouldPanelOpen({
84
- state: store.getState()
85
- });
86
- setIsOpen((_nextState$isOpen2 = nextState.isOpen) !== null && _nextState$isOpen2 !== void 0 ? _nextState$isOpen2 : props.openOnFocus && !query && isPanelOpen || isPanelOpen);
87
- var highlightedItem = getActiveItem(store.getState());
88
-
89
- if (store.getState().activeItemId !== null && highlightedItem) {
90
- var item = highlightedItem.item,
91
- itemInputValue = highlightedItem.itemInputValue,
92
- itemUrl = highlightedItem.itemUrl,
93
- source = highlightedItem.source;
94
- source.onActive(_objectSpread({
95
- event: event,
96
- item: item,
97
- itemInputValue: itemInputValue,
98
- itemUrl: itemUrl,
99
- refresh: refresh,
100
- source: source,
101
- state: store.getState()
102
- }, setters));
103
- }
104
- }).finally(function () {
105
- if (lastStalledId) {
106
- props.environment.clearTimeout(lastStalledId);
107
- }
99
+ // Parameters passed to `onInput` could be stale when the following code
100
+ // executes, because `onInput` calls may not resolve in order.
101
+ // If it becomes a problem we'll need to save the last passed parameters.
102
+ // See: https://codesandbox.io/s/agitated-cookies-y290z
103
+ setStatus('idle');
104
+ setCollections(collections);
105
+ var isPanelOpen = props.shouldPanelOpen({
106
+ state: store.getState()
108
107
  });
108
+ setIsOpen((_nextState$isOpen2 = nextState.isOpen) !== null && _nextState$isOpen2 !== void 0 ? _nextState$isOpen2 : props.openOnFocus && !query && isPanelOpen || isPanelOpen);
109
+ var highlightedItem = getActiveItem(store.getState());
110
+
111
+ if (store.getState().activeItemId !== null && highlightedItem) {
112
+ var item = highlightedItem.item,
113
+ itemInputValue = highlightedItem.itemInputValue,
114
+ itemUrl = highlightedItem.itemUrl,
115
+ source = highlightedItem.source;
116
+ source.onActive(_objectSpread({
117
+ event: event,
118
+ item: item,
119
+ itemInputValue: itemInputValue,
120
+ itemUrl: itemUrl,
121
+ refresh: refresh,
122
+ source: source,
123
+ state: store.getState()
124
+ }, setters));
125
+ }
126
+ }).finally(function () {
127
+ setStatus('idle');
128
+
129
+ if (lastStalledId) {
130
+ props.environment.clearTimeout(lastStalledId);
131
+ }
109
132
  });
133
+ return store.pendingRequests.add(request);
110
134
  }
@@ -1,4 +1,6 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ var _excluded = ["event", "props", "refresh", "store"];
2
+
3
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
4
 
3
5
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
6
 
@@ -15,7 +17,7 @@ export function onKeyDown(_ref) {
15
17
  props = _ref.props,
16
18
  refresh = _ref.refresh,
17
19
  store = _ref.store,
18
- setters = _objectWithoutProperties(_ref, ["event", "props", "refresh", "store"]);
20
+ setters = _objectWithoutProperties(_ref, _excluded);
19
21
 
20
22
  if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
21
23
  // eslint-disable-next-line no-inner-declarations
@@ -84,7 +86,12 @@ export function onKeyDown(_ref) {
84
86
  // from removing the query right away because we first want to close the
85
87
  // panel.
86
88
  event.preventDefault();
87
- store.dispatch(event.key, null);
89
+ store.dispatch(event.key, null); // Hitting the `Escape` key signals the end of a user interaction with the
90
+ // autocomplete. At this point, we should ignore any requests that are still
91
+ // pending and could reopen the panel once they resolve, because that would
92
+ // result in an unsolicited UI behavior.
93
+
94
+ store.pendingRequests.cancelAll();
88
95
  } else if (event.key === 'Enter') {
89
96
  // No active item, so we let the browser handle the native `onSubmit` form
90
97
  // event.
@@ -1,4 +1,4 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
2
 
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
4
 
@@ -6,13 +6,13 @@ function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread n
6
6
 
7
7
  function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
8
8
 
9
- function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); }
9
+ function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
10
10
 
11
11
  function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
12
12
 
13
13
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
14
14
 
15
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
15
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
16
16
 
17
17
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
18
18
 
@@ -1,4 +1,4 @@
1
- function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
1
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
2
2
 
3
3
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
4
4
 
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -9,4 +9,5 @@ export declare type AutocompleteEnvironment = Window | {
9
9
  assign: Location['assign'];
10
10
  };
11
11
  open: Window['open'];
12
+ navigator: Window['navigator'];
12
13
  };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -21,5 +21,15 @@ export declare type AutocompletePlugin<TItem extends BaseItem, TData = unknown>
21
21
  * @link https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/plugins/#param-data
22
22
  */
23
23
  data?: TData;
24
+ /**
25
+ * A name to identify the plugin.
26
+ *
27
+ * @link https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/plugins/#param-name
28
+ */
29
+ name?: string;
30
+ /**
31
+ * @internal
32
+ */
33
+ __autocomplete_pluginOptions?: Record<string, any>;
24
34
  };
25
35
  export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -1,9 +1,11 @@
1
+ import { CancelablePromiseList } from '../utils';
1
2
  import { BaseItem } from './AutocompleteApi';
2
3
  import { InternalAutocompleteOptions } from './AutocompleteOptions';
3
4
  import { AutocompleteState } from './AutocompleteState';
4
5
  export interface AutocompleteStore<TItem extends BaseItem> {
5
6
  getState(): AutocompleteState<TItem>;
6
7
  dispatch(action: ActionType, payload: any): void;
8
+ pendingRequests: CancelablePromiseList<void>;
7
9
  }
8
10
  export declare type Reducer = <TItem extends BaseItem>(state: AutocompleteState<TItem>, action: Action<TItem, any>) => AutocompleteState<TItem>;
9
11
  declare type Action<TItem extends BaseItem, TPayload> = {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ declare type PromiseExecutor<TValue> = (resolve: (value: TValue | PromiseLike<TValue>) => void, reject: (reason?: any) => void) => void;
2
+ export declare type CancelablePromise<TValue> = {
3
+ then<TResultFulfilled = TValue, TResultRejected = never>(onfulfilled?: ((value: TValue) => TResultFulfilled | PromiseLike<TResultFulfilled> | CancelablePromise<TResultFulfilled>) | undefined | null, onrejected?: ((reason: any) => TResultRejected | PromiseLike<TResultRejected> | CancelablePromise<TResultRejected>) | undefined | null): CancelablePromise<TResultFulfilled | TResultRejected>;
4
+ catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult> | CancelablePromise<TResult>) | undefined | null): CancelablePromise<TValue | TResult>;
5
+ finally(onfinally?: (() => void) | undefined | null): CancelablePromise<TValue>;
6
+ cancel(): void;
7
+ isCanceled(): boolean;
8
+ };
9
+ export declare function createCancelablePromise<TValue>(executor: PromiseExecutor<TValue>): CancelablePromise<TValue>;
10
+ export declare namespace createCancelablePromise {
11
+ var resolve: <TValue>(value?: TValue | PromiseLike<TValue> | CancelablePromise<TValue> | undefined) => CancelablePromise<TValue | CancelablePromise<TValue> | undefined>;
12
+ var reject: (reason?: any) => CancelablePromise<never>;
13
+ }
14
+ export declare function cancelable<TValue>(promise: Promise<TValue>): CancelablePromise<TValue>;
15
+ export {};