@algolia/autocomplete-core 1.11.0 → 1.12.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.
@@ -28,6 +28,7 @@ export function createAutocomplete(options) {
28
28
  navigator: props.navigator
29
29
  }, setters));
30
30
  function onStoreStateChange(_ref) {
31
+ var _state$context, _state$context$algoli;
31
32
  var prevState = _ref.prevState,
32
33
  state = _ref.state;
33
34
  props.onStateChange(_objectSpread({
@@ -36,6 +37,13 @@ export function createAutocomplete(options) {
36
37
  refresh: refresh,
37
38
  navigator: props.navigator
38
39
  }, setters));
40
+ if (!isAlgoliaInsightsPluginEnabled() && (_state$context = state.context) !== null && _state$context !== void 0 && (_state$context$algoli = _state$context.algoliaInsightsPlugin) !== null && _state$context$algoli !== void 0 && _state$context$algoli.__automaticInsights && props.insights !== false) {
41
+ var plugin = createAlgoliaInsightsPlugin({
42
+ __autocomplete_clickAnalytics: false
43
+ });
44
+ props.plugins.push(plugin);
45
+ subscribePlugins([plugin]);
46
+ }
39
47
  }
40
48
  function refresh() {
41
49
  return onInput(_objectSpread({
@@ -50,34 +58,40 @@ export function createAutocomplete(options) {
50
58
  store: store
51
59
  }, setters));
52
60
  }
53
- if (options.insights && !props.plugins.some(function (plugin) {
54
- return plugin.name === 'aa.algoliaInsightsPlugin';
55
- })) {
56
- var insightsParams = typeof options.insights === 'boolean' ? {} : options.insights;
61
+ function subscribePlugins(plugins) {
62
+ plugins.forEach(function (plugin) {
63
+ var _plugin$subscribe;
64
+ return (_plugin$subscribe = plugin.subscribe) === null || _plugin$subscribe === void 0 ? void 0 : _plugin$subscribe.call(plugin, _objectSpread(_objectSpread({}, setters), {}, {
65
+ navigator: props.navigator,
66
+ refresh: refresh,
67
+ onSelect: function onSelect(fn) {
68
+ subscribers.push({
69
+ onSelect: fn
70
+ });
71
+ },
72
+ onActive: function onActive(fn) {
73
+ subscribers.push({
74
+ onActive: fn
75
+ });
76
+ },
77
+ onResolve: function onResolve(fn) {
78
+ subscribers.push({
79
+ onResolve: fn
80
+ });
81
+ }
82
+ }));
83
+ });
84
+ }
85
+ function isAlgoliaInsightsPluginEnabled() {
86
+ return props.plugins.some(function (plugin) {
87
+ return plugin.name === 'aa.algoliaInsightsPlugin';
88
+ });
89
+ }
90
+ if (props.insights && !isAlgoliaInsightsPluginEnabled()) {
91
+ var insightsParams = typeof props.insights === 'boolean' ? {} : props.insights;
57
92
  props.plugins.push(createAlgoliaInsightsPlugin(insightsParams));
58
93
  }
59
- props.plugins.forEach(function (plugin) {
60
- var _plugin$subscribe;
61
- return (_plugin$subscribe = plugin.subscribe) === null || _plugin$subscribe === void 0 ? void 0 : _plugin$subscribe.call(plugin, _objectSpread(_objectSpread({}, setters), {}, {
62
- navigator: props.navigator,
63
- refresh: refresh,
64
- onSelect: function onSelect(fn) {
65
- subscribers.push({
66
- onSelect: fn
67
- });
68
- },
69
- onActive: function onActive(fn) {
70
- subscribers.push({
71
- onActive: fn
72
- });
73
- },
74
- onResolve: function onResolve(fn) {
75
- subscribers.push({
76
- onResolve: fn
77
- });
78
- }
79
- }));
80
- });
94
+ subscribePlugins(props.plugins);
81
95
  injectMetadata({
82
96
  metadata: getMetadata({
83
97
  plugins: props.plugins,
@@ -26,7 +26,7 @@ export function getDefaultProps(props, pluginSubscribers) {
26
26
  autoFocus: false,
27
27
  defaultActiveItemId: null,
28
28
  stallThreshold: 300,
29
- insights: false,
29
+ insights: undefined,
30
30
  environment: environment,
31
31
  shouldPanelOpen: function shouldPanelOpen(_ref) {
32
32
  var state = _ref.state;
@@ -3,9 +3,8 @@ var _excluded = ["props", "refresh", "store"],
3
3
  _excluded2 = ["inputElement", "formElement", "panelElement"],
4
4
  _excluded3 = ["inputElement"],
5
5
  _excluded4 = ["inputElement", "maxLength"],
6
- _excluded5 = ["sourceIndex"],
7
- _excluded6 = ["sourceIndex"],
8
- _excluded7 = ["item", "source", "sourceIndex"];
6
+ _excluded5 = ["source"],
7
+ _excluded6 = ["item", "source"];
9
8
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
10
9
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
11
10
  function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
@@ -16,7 +15,7 @@ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) r
16
15
  import { noop } from '@algolia/autocomplete-shared';
17
16
  import { onInput } from './onInput';
18
17
  import { onKeyDown as _onKeyDown } from './onKeyDown';
19
- import { getActiveItem, isOrContainsNode, isSamsung } from './utils';
18
+ import { getActiveItem, getAutocompleteElementId, isOrContainsNode, isSamsung } from './utils';
20
19
  export function getPropGetters(_ref) {
21
20
  var props = _ref.props,
22
21
  refresh = _ref.refresh,
@@ -85,8 +84,11 @@ export function getPropGetters(_ref) {
85
84
  role: 'combobox',
86
85
  'aria-expanded': store.getState().isOpen,
87
86
  'aria-haspopup': 'listbox',
88
- 'aria-owns': store.getState().isOpen ? "".concat(props.id, "-list") : undefined,
89
- 'aria-labelledby': "".concat(props.id, "-label")
87
+ 'aria-owns': store.getState().isOpen ? store.getState().collections.map(function (_ref2) {
88
+ var source = _ref2.source;
89
+ return getAutocompleteElementId(props.id, 'list', source);
90
+ }).join(' ') : undefined,
91
+ 'aria-labelledby': getAutocompleteElementId(props.id, 'label')
90
92
  }, rest);
91
93
  };
92
94
  var getFormProps = function getFormProps(providedProps) {
@@ -136,22 +138,25 @@ export function getPropGetters(_ref) {
136
138
  }
137
139
  store.dispatch('focus', null);
138
140
  }
139
- var _ref2 = providedProps || {},
140
- inputElement = _ref2.inputElement,
141
- _ref2$maxLength = _ref2.maxLength,
142
- maxLength = _ref2$maxLength === void 0 ? 512 : _ref2$maxLength,
143
- rest = _objectWithoutProperties(_ref2, _excluded4);
141
+ var _ref3 = providedProps || {},
142
+ inputElement = _ref3.inputElement,
143
+ _ref3$maxLength = _ref3.maxLength,
144
+ maxLength = _ref3$maxLength === void 0 ? 512 : _ref3$maxLength,
145
+ rest = _objectWithoutProperties(_ref3, _excluded4);
144
146
  var activeItem = getActiveItem(store.getState());
145
147
  var userAgent = ((_props$environment$na = props.environment.navigator) === null || _props$environment$na === void 0 ? void 0 : _props$environment$na.userAgent) || '';
146
148
  var shouldFallbackKeyHint = isSamsung(userAgent);
147
149
  var enterKeyHint = props.enterKeyHint || (activeItem !== null && activeItem !== void 0 && activeItem.itemUrl && !shouldFallbackKeyHint ? 'go' : 'search');
148
150
  return _objectSpread({
149
151
  'aria-autocomplete': 'both',
150
- 'aria-activedescendant': store.getState().isOpen && store.getState().activeItemId !== null ? "".concat(props.id, "-item-").concat(store.getState().activeItemId) : undefined,
151
- 'aria-controls': store.getState().isOpen ? "".concat(props.id, "-list") : undefined,
152
- 'aria-labelledby': "".concat(props.id, "-label"),
152
+ 'aria-activedescendant': store.getState().isOpen && store.getState().activeItemId !== null ? getAutocompleteElementId(props.id, "item-".concat(store.getState().activeItemId), activeItem === null || activeItem === void 0 ? void 0 : activeItem.source) : undefined,
153
+ 'aria-controls': store.getState().isOpen ? store.getState().collections.map(function (_ref4) {
154
+ var source = _ref4.source;
155
+ return getAutocompleteElementId(props.id, 'list', source);
156
+ }).join(' ') : undefined,
157
+ 'aria-labelledby': getAutocompleteElementId(props.id, 'label'),
153
158
  value: store.getState().completion || store.getState().query,
154
- id: "".concat(props.id, "-input"),
159
+ id: getAutocompleteElementId(props.id, 'input'),
155
160
  autoComplete: 'off',
156
161
  autoCorrect: 'off',
157
162
  autoCapitalize: 'off',
@@ -197,26 +202,20 @@ export function getPropGetters(_ref) {
197
202
  }
198
203
  }, rest);
199
204
  };
200
- var getAutocompleteId = function getAutocompleteId(instanceId, sourceId) {
201
- return typeof sourceId !== 'undefined' ? "".concat(instanceId, "-").concat(sourceId) : instanceId;
202
- };
203
- var getLabelProps = function getLabelProps(providedProps) {
204
- var _ref3 = providedProps || {},
205
- sourceIndex = _ref3.sourceIndex,
206
- rest = _objectWithoutProperties(_ref3, _excluded5);
205
+ var getLabelProps = function getLabelProps(rest) {
207
206
  return _objectSpread({
208
- htmlFor: "".concat(getAutocompleteId(props.id, sourceIndex), "-input"),
209
- id: "".concat(getAutocompleteId(props.id, sourceIndex), "-label")
207
+ htmlFor: getAutocompleteElementId(props.id, 'input'),
208
+ id: getAutocompleteElementId(props.id, 'label')
210
209
  }, rest);
211
210
  };
212
211
  var getListProps = function getListProps(providedProps) {
213
- var _ref4 = providedProps || {},
214
- sourceIndex = _ref4.sourceIndex,
215
- rest = _objectWithoutProperties(_ref4, _excluded6);
212
+ var _ref5 = providedProps || {},
213
+ source = _ref5.source,
214
+ rest = _objectWithoutProperties(_ref5, _excluded5);
216
215
  return _objectSpread({
217
216
  role: 'listbox',
218
- 'aria-labelledby': "".concat(getAutocompleteId(props.id, sourceIndex), "-label"),
219
- id: "".concat(getAutocompleteId(props.id, sourceIndex), "-list")
217
+ 'aria-labelledby': getAutocompleteElementId(props.id, 'label'),
218
+ id: getAutocompleteElementId(props.id, 'list', source)
220
219
  }, rest);
221
220
  };
222
221
  var getPanelProps = function getPanelProps(rest) {
@@ -235,10 +234,9 @@ export function getPropGetters(_ref) {
235
234
  var getItemProps = function getItemProps(providedProps) {
236
235
  var item = providedProps.item,
237
236
  source = providedProps.source,
238
- sourceIndex = providedProps.sourceIndex,
239
- rest = _objectWithoutProperties(providedProps, _excluded7);
237
+ rest = _objectWithoutProperties(providedProps, _excluded6);
240
238
  return _objectSpread({
241
- id: "".concat(getAutocompleteId(props.id, sourceIndex), "-item-").concat(item.__autocomplete_id),
239
+ id: getAutocompleteElementId(props.id, "item-".concat(item.__autocomplete_id), source),
242
240
  role: 'option',
243
241
  'aria-selected': store.getState().activeItemId === item.__autocomplete_id,
244
242
  onMouseMove: function onMouseMove(event) {
@@ -28,7 +28,8 @@ export function onInput(_ref) {
28
28
  setIsOpen = setters.setIsOpen,
29
29
  setQuery = setters.setQuery,
30
30
  setActiveItemId = setters.setActiveItemId,
31
- setStatus = setters.setStatus;
31
+ setStatus = setters.setStatus,
32
+ setContext = setters.setContext;
32
33
  setQuery(query);
33
34
  setActiveItemId(props.defaultActiveItemId);
34
35
  if (!query && props.openOnFocus === false) {
@@ -78,6 +79,20 @@ export function onInput(_ref) {
78
79
  return preResolve(itemsOrDescription, source.sourceId, store.getState());
79
80
  });
80
81
  })).then(resolve).then(function (responses) {
82
+ var __automaticInsights = responses.some(function (_ref2) {
83
+ var items = _ref2.items;
84
+ return isSearchResponseWithAutomaticInsightsFlag(items);
85
+ });
86
+
87
+ // No need to pollute the context if `__automaticInsights=false`
88
+ if (__automaticInsights) {
89
+ var _store$getState$conte;
90
+ setContext({
91
+ algoliaInsightsPlugin: _objectSpread(_objectSpread({}, ((_store$getState$conte = store.getState().context) === null || _store$getState$conte === void 0 ? void 0 : _store$getState$conte.algoliaInsightsPlugin) || {}), {}, {
92
+ __automaticInsights: __automaticInsights
93
+ })
94
+ });
95
+ }
81
96
  return postResolve(responses, sources, store);
82
97
  }).then(function (collections) {
83
98
  return reshape({
@@ -122,4 +137,7 @@ export function onInput(_ref) {
122
137
  }
123
138
  });
124
139
  return store.pendingRequests.add(request);
140
+ }
141
+ function isSearchResponseWithAutomaticInsightsFlag(items) {
142
+ return !Array.isArray(items) && Boolean(items === null || items === void 0 ? void 0 : items._automaticInsights);
125
143
  }
@@ -8,7 +8,7 @@ function _toPrimitive(input, hint) { if (_typeof(input) !== "object" || input ==
8
8
  function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
9
9
  function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
10
10
  import { onInput } from './onInput';
11
- import { getActiveItem } from './utils';
11
+ import { getActiveItem, getAutocompleteElementId } from './utils';
12
12
  export function onKeyDown(_ref) {
13
13
  var event = _ref.event,
14
14
  props = _ref.props,
@@ -18,7 +18,8 @@ export function onKeyDown(_ref) {
18
18
  if (event.key === 'ArrowUp' || event.key === 'ArrowDown') {
19
19
  // eslint-disable-next-line no-inner-declarations
20
20
  var triggerScrollIntoView = function triggerScrollIntoView() {
21
- var nodeItem = props.environment.document.getElementById("".concat(props.id, "-item-").concat(store.getState().activeItemId));
21
+ var highlightedItem = getActiveItem(store.getState());
22
+ var nodeItem = props.environment.document.getElementById(getAutocompleteElementId(props.id, "item-".concat(store.getState().activeItemId), highlightedItem === null || highlightedItem === void 0 ? void 0 : highlightedItem.source));
22
23
  if (nodeItem) {
23
24
  if (nodeItem.scrollIntoViewIfNeeded) {
24
25
  nodeItem.scrollIntoViewIfNeeded(false);
@@ -1,5 +1,6 @@
1
1
  import type { ExecuteResponse, RequesterDescription, TransformResponse } from '@algolia/autocomplete-preset-algolia';
2
- import { MultipleQueriesQuery, SearchForFacetValuesResponse, SearchResponse } from '@algolia/client-search';
2
+ import type { SearchResponse } from '@algolia/autocomplete-shared';
3
+ import { MultipleQueriesQuery, SearchForFacetValuesResponse } from '@algolia/client-search';
3
4
  import { AutocompleteState, AutocompleteStore, BaseItem, InternalAutocompleteSource } from './types';
4
5
  declare type RequestDescriptionPreResolved<TItem extends BaseItem> = Pick<RequesterDescription<TItem>, 'execute' | 'requesterId' | 'searchClient' | 'transformResponse'> & {
5
6
  requests: Array<{
@@ -2,17 +2,21 @@ export * from '@algolia/autocomplete-shared/dist/esm/core';
2
2
  export * from './AutocompleteStore';
3
3
  export * from './AutocompleteSubscribers';
4
4
  import { CreateAlgoliaInsightsPluginParams, AutocompleteInsightsApi as _AutocompleteInsightsApi, AlgoliaInsightsHit as _AlgoliaInsightsHit } from '@algolia/autocomplete-plugin-algolia-insights';
5
- import { AutocompleteOptions as _AutocompleteOptions, BaseItem } from '@algolia/autocomplete-shared/dist/esm/core';
5
+ import { AutocompleteOptions as _AutocompleteOptions, InternalAutocompleteOptions as _InternalAutocompleteOptions, BaseItem } from '@algolia/autocomplete-shared/dist/esm/core';
6
6
  export declare type AutocompleteInsightsApi = _AutocompleteInsightsApi;
7
7
  export declare type AlgoliaInsightsHit = _AlgoliaInsightsHit;
8
- export interface AutocompleteOptions<TItem extends BaseItem> extends _AutocompleteOptions<TItem> {
8
+ declare type InsightsOption = {
9
9
  /**
10
10
  * Whether to enable the Insights plugin and load the Insights library if it has not been loaded yet.
11
11
  *
12
12
  * See [**autocomplete-plugin-algolia-insights**](https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-plugin-algolia-insights/) for more information.
13
13
  *
14
- * @default false
14
+ * @default undefined
15
15
  * @link https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-insights
16
16
  */
17
- insights?: CreateAlgoliaInsightsPluginParams | boolean;
17
+ insights?: CreateAlgoliaInsightsPluginParams | boolean | undefined;
18
+ };
19
+ export interface AutocompleteOptions<TItem extends BaseItem> extends _AutocompleteOptions<TItem>, InsightsOption {
20
+ }
21
+ export interface InternalAutocompleteOptions<TItem extends BaseItem> extends _InternalAutocompleteOptions<TItem>, InsightsOption {
18
22
  }
@@ -0,0 +1,9 @@
1
+ import type { InternalAutocompleteSource } from '../types';
2
+ /**
3
+ * Returns a full element id for an autocomplete element.
4
+ *
5
+ * @param autocompleteInstanceId The id of the autocomplete instance
6
+ * @param elementId The specific element id
7
+ * @param source The source of the element, when it needs to be scoped
8
+ */
9
+ export declare function getAutocompleteElementId(autocompleteInstanceId: string, elementId: string, source?: InternalAutocompleteSource<any>): string;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Returns a full element id for an autocomplete element.
3
+ *
4
+ * @param autocompleteInstanceId The id of the autocomplete instance
5
+ * @param elementId The specific element id
6
+ * @param source The source of the element, when it needs to be scoped
7
+ */
8
+ export function getAutocompleteElementId(autocompleteInstanceId, elementId, source) {
9
+ return [autocompleteInstanceId, source === null || source === void 0 ? void 0 : source.sourceId, elementId].filter(Boolean).join('-').replace(/\s/g, '');
10
+ }
@@ -4,6 +4,7 @@ export * from './createConcurrentSafePromise';
4
4
  export * from './getNextActiveItemId';
5
5
  export * from './getNormalizedSources';
6
6
  export * from './getActiveItem';
7
+ export * from './getAutocompleteElementId';
7
8
  export * from './isOrContainsNode';
8
9
  export * from './isSamsung';
9
10
  export * from './mapToAlgoliaResponse';
@@ -4,6 +4,7 @@ export * from './createConcurrentSafePromise';
4
4
  export * from './getNextActiveItemId';
5
5
  export * from './getNormalizedSources';
6
6
  export * from './getActiveItem';
7
+ export * from './getAutocompleteElementId';
7
8
  export * from './isOrContainsNode';
8
9
  export * from './isSamsung';
9
10
  export * from './mapToAlgoliaResponse';
@@ -1,4 +1,5 @@
1
- import type { SearchForFacetValuesResponse, SearchResponse } from '@algolia/client-search';
1
+ import type { SearchResponse } from '@algolia/autocomplete-shared';
2
+ import type { SearchForFacetValuesResponse } from '@algolia/client-search';
2
3
  export declare function mapToAlgoliaResponse<THit>(rawResults: Array<SearchResponse<THit> | SearchForFacetValuesResponse>): {
3
4
  results: (SearchResponse<THit> | SearchForFacetValuesResponse)[];
4
5
  hits: import("@algolia/client-search").Hit<THit>[][];