@algolia/autocomplete-js 1.19.9 → 1.19.11

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.
@@ -36,6 +36,19 @@ export function autocomplete(options) {
36
36
  var isDetached = reactive(function () {
37
37
  return props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
38
38
  });
39
+ function warnAboutOpenOnFocusInDetachedMode() {
40
+ var _props$value$core$ope;
41
+ // `openOnFocus` isn't resolved to its default at this layer yet (that
42
+ // happens inside `autocomplete-core`'s `createAutocomplete`), so we
43
+ // mirror its documented default (`false`) explicitly here rather than
44
+ // relying on falsiness, or reaching for `getDefaultProps` from
45
+ // `autocomplete-core` — that function has side effects (it generates
46
+ // an autocomplete id, builds the full `getSources` pipeline) that make
47
+ // it unsuitable for just reading one resolved option.
48
+ var openOnFocus = (_props$value$core$ope = props.value.core.openOnFocus) !== null && _props$value$core$ope !== void 0 ? _props$value$core$ope : false;
49
+ process.env.NODE_ENV !== 'production' ? warn(!(isDetached.value && !openOnFocus), "`openOnFocus: false` can lead to unexpected behavior in detached mode. We recommend using `openOnFocus: true` when detached mode is enabled.\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-openonfocus") : void 0;
50
+ }
51
+ warnAboutOpenOnFocusInDetachedMode();
39
52
  var autocomplete = reactive(function () {
40
53
  return createAutocomplete(_objectSpread(_objectSpread({}, props.value.core), {}, {
41
54
  onStateChange: function onStateChange(params) {
@@ -116,6 +129,7 @@ export function autocomplete(options) {
116
129
  panelPlacement: props.value.renderer.panelPlacement,
117
130
  container: dom.value.root,
118
131
  form: dom.value.form,
132
+ panel: dom.value.panel,
119
133
  environment: props.value.core.environment
120
134
  })
121
135
  });
@@ -138,6 +152,7 @@ export function autocomplete(options) {
138
152
  var render = !getItemsCount(state) && !hasNoResultsSourceTemplateRef.current && props.value.renderer.renderNoResults || props.value.renderer.render;
139
153
  renderSearchBox(renderProps);
140
154
  renderPanel(render, renderProps);
155
+ requestAnimationFrame(setPanelPosition);
141
156
  }
142
157
  runEffect(function () {
143
158
  var environmentProps = autocomplete.value.getEnvironmentProps({
@@ -216,6 +231,7 @@ export function autocomplete(options) {
216
231
  var previousIsDetached = isDetached.value;
217
232
  isDetached.value = props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
218
233
  if (previousIsDetached !== isDetached.value) {
234
+ warnAboutOpenOnFocusInDetachedMode();
219
235
  update({});
220
236
  } else {
221
237
  requestAnimationFrame(setPanelPosition);
@@ -2,8 +2,9 @@ import { AutocompleteOptions } from './types';
2
2
  declare type GetPanelPlacementStyleParams = Pick<Required<AutocompleteOptions<any>>, 'panelPlacement' | 'environment'> & {
3
3
  container: HTMLElement;
4
4
  form: HTMLElement;
5
+ panel: HTMLElement;
5
6
  };
6
- export declare function getPanelPlacementStyle({ panelPlacement, container, form, environment, }: GetPanelPlacementStyleParams): {
7
+ export declare function getPanelPlacementStyle({ panelPlacement, container, form, panel, environment, }: GetPanelPlacementStyleParams): {
7
8
  top: number;
8
9
  left: number;
9
10
  right?: undefined;
@@ -2,31 +2,43 @@ export function getPanelPlacementStyle(_ref) {
2
2
  var panelPlacement = _ref.panelPlacement,
3
3
  container = _ref.container,
4
4
  form = _ref.form,
5
+ panel = _ref.panel,
5
6
  environment = _ref.environment;
6
7
  var containerRect = container.getBoundingClientRect();
7
8
  // Some browsers have specificities to retrieve the document scroll position.
8
9
  // See https://stackoverflow.com/a/28633515/9940315
9
10
  var scrollTop = environment.pageYOffset || environment.document.documentElement.scrollTop || environment.document.body.scrollTop || 0;
11
+ var panelHeight = panel.offsetHeight;
12
+ var panelStyle = 'getComputedStyle' in environment && typeof environment.getComputedStyle === 'function' ? environment.getComputedStyle(panel) : panel.style;
13
+ var panelMarginTop = parseFloat(panelStyle.marginTop) || 0;
14
+ var panelMarginBottom = parseFloat(panelStyle.marginBottom) || 0;
15
+ var panelHeightWithMargins = panelHeight + panelMarginTop + panelMarginBottom;
16
+ var panelHeightAbove = panelHeight + panelMarginTop * 2;
10
17
  var top = scrollTop + containerRect.top + containerRect.height;
18
+ var panelTop = scrollTop + containerRect.top - panelHeightAbove;
19
+ var bottomSpace = environment.document.documentElement.clientHeight - (containerRect.top + containerRect.height);
20
+ var topSpace = containerRect.top;
21
+ var shouldPlacePanelAbove = panelHeightWithMargins > 0 && bottomSpace < panelHeightWithMargins && topSpace >= panelHeightAbove;
22
+ var verticalPosition = shouldPlacePanelAbove ? panelTop : top;
11
23
  switch (panelPlacement) {
12
24
  case 'start':
13
25
  {
14
26
  return {
15
- top: top,
27
+ top: verticalPosition,
16
28
  left: containerRect.left
17
29
  };
18
30
  }
19
31
  case 'end':
20
32
  {
21
33
  return {
22
- top: top,
34
+ top: verticalPosition,
23
35
  right: environment.document.documentElement.clientWidth - (containerRect.left + containerRect.width)
24
36
  };
25
37
  }
26
38
  case 'full-width':
27
39
  {
28
40
  return {
29
- top: top,
41
+ top: verticalPosition,
30
42
  left: 0,
31
43
  right: 0,
32
44
  width: 'unset',
@@ -37,7 +49,7 @@ export function getPanelPlacementStyle(_ref) {
37
49
  {
38
50
  var formRect = form.getBoundingClientRect();
39
51
  return {
40
- top: top,
52
+ top: verticalPosition,
41
53
  left: formRect.left,
42
54
  right: environment.document.documentElement.clientWidth - (formRect.left + formRect.width),
43
55
  width: 'unset',
@@ -1,4 +1,4 @@
1
- /*! @algolia/autocomplete-js 1.19.9 | MIT License | © Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */
1
+ /*! @algolia/autocomplete-js 1.19.11 | 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) :
@@ -327,7 +327,7 @@
327
327
  return undefined;
328
328
  }
329
329
 
330
- var version = '1.19.9';
330
+ var version = '1.19.11';
331
331
 
332
332
  var userAgents$1 = [{
333
333
  segment: 'autocomplete-core',
@@ -2518,9 +2518,11 @@
2518
2518
  // result in an unsolicited UI behavior.
2519
2519
  store.pendingRequests.cancelAll();
2520
2520
  } else if (event.key === 'Enter') {
2521
+ var activeItem = store.getState().activeItemId !== null ? getActiveItem(store.getState()) : null;
2522
+
2521
2523
  // No active item, so we let the browser handle the native `onSubmit` form
2522
2524
  // event.
2523
- if (store.getState().activeItemId === null || store.getState().collections.every(function (collection) {
2525
+ if (!activeItem || store.getState().collections.every(function (collection) {
2524
2526
  return collection.items.length === 0;
2525
2527
  })) {
2526
2528
  var waitForSubmit = getPluginSubmitPromise(props.plugins, store.pendingRequests);
@@ -2539,11 +2541,10 @@
2539
2541
  // This prevents the `onSubmit` event to be sent because an item is
2540
2542
  // highlighted.
2541
2543
  event.preventDefault();
2542
- var _ref2 = getActiveItem(store.getState()),
2543
- item = _ref2.item,
2544
- itemInputValue = _ref2.itemInputValue,
2545
- itemUrl = _ref2.itemUrl,
2546
- source = _ref2.source;
2544
+ var item = activeItem.item,
2545
+ itemInputValue = activeItem.itemInputValue,
2546
+ itemUrl = activeItem.itemUrl,
2547
+ source = activeItem.source;
2547
2548
  if (event.metaKey || event.ctrlKey) {
2548
2549
  if (itemUrl !== undefined) {
2549
2550
  source.onSelect(_objectSpread$7({
@@ -3193,9 +3194,13 @@
3193
3194
  }
3194
3195
  case 'setCollections':
3195
3196
  {
3196
- return _objectSpread$4(_objectSpread$4({}, state), {}, {
3197
+ var newItemsCount = getItemsCount({
3197
3198
  collections: action.payload
3198
3199
  });
3200
+ return _objectSpread$4(_objectSpread$4({}, state), {}, {
3201
+ collections: action.payload,
3202
+ activeItemId: state.activeItemId !== null && state.activeItemId >= newItemsCount ? action.props.defaultActiveItemId : state.activeItemId
3203
+ });
3199
3204
  }
3200
3205
  case 'setIsOpen':
3201
3206
  {
@@ -4663,31 +4668,43 @@
4663
4668
  var panelPlacement = _ref.panelPlacement,
4664
4669
  container = _ref.container,
4665
4670
  form = _ref.form,
4671
+ panel = _ref.panel,
4666
4672
  environment = _ref.environment;
4667
4673
  var containerRect = container.getBoundingClientRect();
4668
4674
  // Some browsers have specificities to retrieve the document scroll position.
4669
4675
  // See https://stackoverflow.com/a/28633515/9940315
4670
4676
  var scrollTop = environment.pageYOffset || environment.document.documentElement.scrollTop || environment.document.body.scrollTop || 0;
4677
+ var panelHeight = panel.offsetHeight;
4678
+ var panelStyle = 'getComputedStyle' in environment && typeof environment.getComputedStyle === 'function' ? environment.getComputedStyle(panel) : panel.style;
4679
+ var panelMarginTop = parseFloat(panelStyle.marginTop) || 0;
4680
+ var panelMarginBottom = parseFloat(panelStyle.marginBottom) || 0;
4681
+ var panelHeightWithMargins = panelHeight + panelMarginTop + panelMarginBottom;
4682
+ var panelHeightAbove = panelHeight + panelMarginTop * 2;
4671
4683
  var top = scrollTop + containerRect.top + containerRect.height;
4684
+ var panelTop = scrollTop + containerRect.top - panelHeightAbove;
4685
+ var bottomSpace = environment.document.documentElement.clientHeight - (containerRect.top + containerRect.height);
4686
+ var topSpace = containerRect.top;
4687
+ var shouldPlacePanelAbove = panelHeightWithMargins > 0 && bottomSpace < panelHeightWithMargins && topSpace >= panelHeightAbove;
4688
+ var verticalPosition = shouldPlacePanelAbove ? panelTop : top;
4672
4689
  switch (panelPlacement) {
4673
4690
  case 'start':
4674
4691
  {
4675
4692
  return {
4676
- top: top,
4693
+ top: verticalPosition,
4677
4694
  left: containerRect.left
4678
4695
  };
4679
4696
  }
4680
4697
  case 'end':
4681
4698
  {
4682
4699
  return {
4683
- top: top,
4700
+ top: verticalPosition,
4684
4701
  right: environment.document.documentElement.clientWidth - (containerRect.left + containerRect.width)
4685
4702
  };
4686
4703
  }
4687
4704
  case 'full-width':
4688
4705
  {
4689
4706
  return {
4690
- top: top,
4707
+ top: verticalPosition,
4691
4708
  left: 0,
4692
4709
  right: 0,
4693
4710
  width: 'unset',
@@ -4698,7 +4715,7 @@
4698
4715
  {
4699
4716
  var formRect = form.getBoundingClientRect();
4700
4717
  return {
4701
- top: top,
4718
+ top: verticalPosition,
4702
4719
  left: formRect.left,
4703
4720
  right: environment.document.documentElement.clientWidth - (formRect.left + formRect.width),
4704
4721
  width: 'unset',
@@ -4899,6 +4916,19 @@
4899
4916
  var isDetached = reactive(function () {
4900
4917
  return props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
4901
4918
  });
4919
+ function warnAboutOpenOnFocusInDetachedMode() {
4920
+ var _props$value$core$ope;
4921
+ // `openOnFocus` isn't resolved to its default at this layer yet (that
4922
+ // happens inside `autocomplete-core`'s `createAutocomplete`), so we
4923
+ // mirror its documented default (`false`) explicitly here rather than
4924
+ // relying on falsiness, or reaching for `getDefaultProps` from
4925
+ // `autocomplete-core` — that function has side effects (it generates
4926
+ // an autocomplete id, builds the full `getSources` pipeline) that make
4927
+ // it unsuitable for just reading one resolved option.
4928
+ var openOnFocus = (_props$value$core$ope = props.value.core.openOnFocus) !== null && _props$value$core$ope !== void 0 ? _props$value$core$ope : false;
4929
+ "development" !== 'production' ? warn(!(isDetached.value && !openOnFocus), "`openOnFocus: false` can lead to unexpected behavior in detached mode. We recommend using `openOnFocus: true` when detached mode is enabled.\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/api-reference/autocomplete-js/autocomplete/#param-openonfocus") : void 0;
4930
+ }
4931
+ warnAboutOpenOnFocusInDetachedMode();
4902
4932
  var autocomplete = reactive(function () {
4903
4933
  return createAutocomplete(_objectSpread2(_objectSpread2({}, props.value.core), {}, {
4904
4934
  onStateChange: function onStateChange(params) {
@@ -4979,6 +5009,7 @@
4979
5009
  panelPlacement: props.value.renderer.panelPlacement,
4980
5010
  container: dom.value.root,
4981
5011
  form: dom.value.form,
5012
+ panel: dom.value.panel,
4982
5013
  environment: props.value.core.environment
4983
5014
  })
4984
5015
  });
@@ -5001,6 +5032,7 @@
5001
5032
  var render = !getItemsCount(state) && !hasNoResultsSourceTemplateRef.current && props.value.renderer.renderNoResults || props.value.renderer.render;
5002
5033
  renderSearchBox(renderProps);
5003
5034
  renderPanel(render, renderProps);
5035
+ requestAnimationFrame(setPanelPosition);
5004
5036
  }
5005
5037
  runEffect(function () {
5006
5038
  var environmentProps = autocomplete.value.getEnvironmentProps({
@@ -5079,6 +5111,7 @@
5079
5111
  var previousIsDetached = isDetached.value;
5080
5112
  isDetached.value = props.value.core.environment.matchMedia(props.value.renderer.detachedMediaQuery).matches;
5081
5113
  if (previousIsDetached !== isDetached.value) {
5114
+ warnAboutOpenOnFocusInDetachedMode();
5082
5115
  update({});
5083
5116
  } else {
5084
5117
  requestAnimationFrame(setPanelPosition);