primeng 16.6.0 → 16.7.1

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 (179) hide show
  1. package/animate/animate.d.ts +3 -2
  2. package/animateonscroll/animateonscroll.d.ts +73 -0
  3. package/animateonscroll/index.d.ts +5 -0
  4. package/animateonscroll/public_api.d.ts +1 -0
  5. package/api/primengconfig.d.ts +1 -0
  6. package/autocomplete/autocomplete.d.ts +177 -54
  7. package/autocomplete/autocomplete.interface.d.ts +30 -0
  8. package/cascadeselect/cascadeselect.d.ts +188 -68
  9. package/cascadeselect/cascadeselect.interface.d.ts +19 -0
  10. package/checkbox/checkbox.d.ts +1 -4
  11. package/chips/chips.d.ts +21 -5
  12. package/colorpicker/colorpicker.d.ts +5 -5
  13. package/contextmenu/contextmenu.d.ts +1 -0
  14. package/dialog/dialog.d.ts +1 -2
  15. package/dom/domhandler.d.ts +4 -1
  16. package/dropdown/dropdown.d.ts +115 -37
  17. package/esm2022/accordion/accordion.mjs +11 -7
  18. package/esm2022/animate/animate.mjs +4 -1
  19. package/esm2022/animateonscroll/animateonscroll.mjs +185 -0
  20. package/esm2022/animateonscroll/primeng-animateonscroll.mjs +5 -0
  21. package/esm2022/animateonscroll/public_api.mjs +2 -0
  22. package/esm2022/api/primengconfig.mjs +2 -1
  23. package/esm2022/autocomplete/autocomplete.interface.mjs +1 -1
  24. package/esm2022/autocomplete/autocomplete.mjs +893 -617
  25. package/esm2022/carousel/carousel.mjs +5 -1
  26. package/esm2022/cascadeselect/cascadeselect.interface.mjs +1 -1
  27. package/esm2022/cascadeselect/cascadeselect.mjs +921 -482
  28. package/esm2022/checkbox/checkbox.mjs +90 -73
  29. package/esm2022/chips/chips.mjs +197 -53
  30. package/esm2022/colorpicker/colorpicker.mjs +56 -37
  31. package/esm2022/contextmenu/contextmenu.mjs +10 -1
  32. package/esm2022/dialog/dialog.mjs +6 -11
  33. package/esm2022/dom/domhandler.mjs +26 -8
  34. package/esm2022/dropdown/dropdown.mjs +711 -587
  35. package/esm2022/inputmask/inputmask.mjs +22 -9
  36. package/esm2022/inputnumber/inputnumber.mjs +142 -83
  37. package/esm2022/inputswitch/inputswitch.mjs +55 -49
  38. package/esm2022/knob/knob.mjs +92 -5
  39. package/esm2022/listbox/listbox.interface.mjs +1 -1
  40. package/esm2022/listbox/listbox.mjs +998 -455
  41. package/esm2022/multiselect/multiselect.mjs +1024 -604
  42. package/esm2022/overlaypanel/overlaypanel.mjs +2 -2
  43. package/esm2022/paginator/paginator.mjs +2 -2
  44. package/esm2022/password/password.mjs +29 -28
  45. package/esm2022/radiobutton/radiobutton.mjs +46 -33
  46. package/esm2022/rating/rating.mjs +172 -80
  47. package/esm2022/selectbutton/selectbutton.mjs +105 -33
  48. package/esm2022/slider/slider.mjs +151 -66
  49. package/esm2022/table/table.mjs +3 -3
  50. package/esm2022/togglebutton/togglebutton.mjs +47 -10
  51. package/esm2022/treetable/treetable.mjs +21 -25
  52. package/esm2022/tristatecheckbox/tristatecheckbox.mjs +53 -35
  53. package/fesm2022/primeng-accordion.mjs +10 -6
  54. package/fesm2022/primeng-accordion.mjs.map +1 -1
  55. package/fesm2022/primeng-animate.mjs +3 -0
  56. package/fesm2022/primeng-animate.mjs.map +1 -1
  57. package/fesm2022/primeng-animateonscroll.mjs +190 -0
  58. package/fesm2022/primeng-animateonscroll.mjs.map +1 -0
  59. package/fesm2022/primeng-api.mjs +1 -0
  60. package/fesm2022/primeng-api.mjs.map +1 -1
  61. package/fesm2022/primeng-autocomplete.mjs +893 -617
  62. package/fesm2022/primeng-autocomplete.mjs.map +1 -1
  63. package/fesm2022/primeng-carousel.mjs +4 -0
  64. package/fesm2022/primeng-carousel.mjs.map +1 -1
  65. package/fesm2022/primeng-cascadeselect.mjs +920 -481
  66. package/fesm2022/primeng-cascadeselect.mjs.map +1 -1
  67. package/fesm2022/primeng-checkbox.mjs +89 -72
  68. package/fesm2022/primeng-checkbox.mjs.map +1 -1
  69. package/fesm2022/primeng-chips.mjs +195 -51
  70. package/fesm2022/primeng-chips.mjs.map +1 -1
  71. package/fesm2022/primeng-colorpicker.mjs +55 -36
  72. package/fesm2022/primeng-colorpicker.mjs.map +1 -1
  73. package/fesm2022/primeng-contextmenu.mjs +9 -0
  74. package/fesm2022/primeng-contextmenu.mjs.map +1 -1
  75. package/fesm2022/primeng-dialog.mjs +5 -10
  76. package/fesm2022/primeng-dialog.mjs.map +1 -1
  77. package/fesm2022/primeng-dom.mjs +25 -7
  78. package/fesm2022/primeng-dom.mjs.map +1 -1
  79. package/fesm2022/primeng-dropdown.mjs +710 -586
  80. package/fesm2022/primeng-dropdown.mjs.map +1 -1
  81. package/fesm2022/primeng-inputmask.mjs +20 -7
  82. package/fesm2022/primeng-inputmask.mjs.map +1 -1
  83. package/fesm2022/primeng-inputnumber.mjs +140 -81
  84. package/fesm2022/primeng-inputnumber.mjs.map +1 -1
  85. package/fesm2022/primeng-inputswitch.mjs +55 -49
  86. package/fesm2022/primeng-inputswitch.mjs.map +1 -1
  87. package/fesm2022/primeng-knob.mjs +92 -5
  88. package/fesm2022/primeng-knob.mjs.map +1 -1
  89. package/fesm2022/primeng-listbox.mjs +997 -454
  90. package/fesm2022/primeng-listbox.mjs.map +1 -1
  91. package/fesm2022/primeng-multiselect.mjs +1023 -603
  92. package/fesm2022/primeng-multiselect.mjs.map +1 -1
  93. package/fesm2022/primeng-overlaypanel.mjs +1 -1
  94. package/fesm2022/primeng-overlaypanel.mjs.map +1 -1
  95. package/fesm2022/primeng-paginator.mjs +1 -1
  96. package/fesm2022/primeng-paginator.mjs.map +1 -1
  97. package/fesm2022/primeng-password.mjs +27 -26
  98. package/fesm2022/primeng-password.mjs.map +1 -1
  99. package/fesm2022/primeng-radiobutton.mjs +46 -33
  100. package/fesm2022/primeng-radiobutton.mjs.map +1 -1
  101. package/fesm2022/primeng-rating.mjs +171 -79
  102. package/fesm2022/primeng-rating.mjs.map +1 -1
  103. package/fesm2022/primeng-selectbutton.mjs +104 -32
  104. package/fesm2022/primeng-selectbutton.mjs.map +1 -1
  105. package/fesm2022/primeng-slider.mjs +150 -65
  106. package/fesm2022/primeng-slider.mjs.map +1 -1
  107. package/fesm2022/primeng-table.mjs +2 -2
  108. package/fesm2022/primeng-table.mjs.map +1 -1
  109. package/fesm2022/primeng-togglebutton.mjs +46 -9
  110. package/fesm2022/primeng-togglebutton.mjs.map +1 -1
  111. package/fesm2022/primeng-treetable.mjs +23 -27
  112. package/fesm2022/primeng-treetable.mjs.map +1 -1
  113. package/fesm2022/primeng-tristatecheckbox.mjs +53 -35
  114. package/fesm2022/primeng-tristatecheckbox.mjs.map +1 -1
  115. package/inputmask/inputmask.d.ts +6 -1
  116. package/inputnumber/inputnumber.d.ts +6 -1
  117. package/inputswitch/inputswitch.d.ts +6 -9
  118. package/knob/knob.d.ts +20 -3
  119. package/listbox/listbox.d.ts +208 -39
  120. package/listbox/listbox.interface.d.ts +16 -1
  121. package/multiselect/multiselect.d.ts +171 -60
  122. package/package.json +138 -132
  123. package/password/password.d.ts +3 -4
  124. package/radiobutton/radiobutton.d.ts +1 -2
  125. package/rating/rating.d.ts +29 -7
  126. package/resources/components/dropdown/dropdown.css +16 -2
  127. package/resources/themes/arya-blue/theme.css +106 -84
  128. package/resources/themes/arya-green/theme.css +106 -84
  129. package/resources/themes/arya-orange/theme.css +106 -84
  130. package/resources/themes/arya-purple/theme.css +106 -84
  131. package/resources/themes/bootstrap4-dark-blue/theme.css +110 -88
  132. package/resources/themes/bootstrap4-dark-purple/theme.css +110 -88
  133. package/resources/themes/bootstrap4-light-blue/theme.css +110 -88
  134. package/resources/themes/bootstrap4-light-purple/theme.css +110 -88
  135. package/resources/themes/fluent-light/theme.css +103 -81
  136. package/resources/themes/lara-dark-blue/theme.css +106 -84
  137. package/resources/themes/lara-dark-indigo/theme.css +106 -84
  138. package/resources/themes/lara-dark-purple/theme.css +106 -84
  139. package/resources/themes/lara-dark-teal/theme.css +106 -84
  140. package/resources/themes/lara-light-blue/theme.css +109 -87
  141. package/resources/themes/lara-light-indigo/theme.css +109 -87
  142. package/resources/themes/lara-light-purple/theme.css +109 -87
  143. package/resources/themes/lara-light-teal/theme.css +109 -87
  144. package/resources/themes/luna-amber/theme.css +110 -88
  145. package/resources/themes/luna-blue/theme.css +110 -88
  146. package/resources/themes/luna-green/theme.css +110 -88
  147. package/resources/themes/luna-pink/theme.css +110 -88
  148. package/resources/themes/md-dark-deeppurple/theme.css +117 -95
  149. package/resources/themes/md-dark-indigo/theme.css +117 -95
  150. package/resources/themes/md-light-deeppurple/theme.css +117 -95
  151. package/resources/themes/md-light-indigo/theme.css +117 -95
  152. package/resources/themes/mdc-dark-deeppurple/theme.css +117 -95
  153. package/resources/themes/mdc-dark-indigo/theme.css +117 -95
  154. package/resources/themes/mdc-light-deeppurple/theme.css +117 -95
  155. package/resources/themes/mdc-light-indigo/theme.css +117 -95
  156. package/resources/themes/mira/theme.css +107 -85
  157. package/resources/themes/nano/theme.css +109 -87
  158. package/resources/themes/nova/theme.css +110 -88
  159. package/resources/themes/nova-accent/theme.css +109 -87
  160. package/resources/themes/nova-alt/theme.css +110 -88
  161. package/resources/themes/rhea/theme.css +109 -87
  162. package/resources/themes/saga-blue/theme.css +106 -84
  163. package/resources/themes/saga-green/theme.css +106 -84
  164. package/resources/themes/saga-orange/theme.css +106 -84
  165. package/resources/themes/saga-purple/theme.css +106 -84
  166. package/resources/themes/soho-dark/theme.css +109 -87
  167. package/resources/themes/soho-light/theme.css +109 -87
  168. package/resources/themes/tailwind-light/theme.css +110 -88
  169. package/resources/themes/vela-blue/theme.css +106 -84
  170. package/resources/themes/vela-green/theme.css +106 -84
  171. package/resources/themes/vela-orange/theme.css +106 -84
  172. package/resources/themes/vela-purple/theme.css +106 -84
  173. package/resources/themes/viva-dark/theme.css +109 -87
  174. package/resources/themes/viva-light/theme.css +109 -87
  175. package/selectbutton/selectbutton.d.ts +15 -3
  176. package/slider/slider.d.ts +12 -6
  177. package/togglebutton/togglebutton.d.ts +7 -1
  178. package/treetable/treetable.d.ts +3 -4
  179. package/tristatecheckbox/tristatecheckbox.d.ts +8 -4
@@ -1,10 +1,10 @@
1
1
  import * as i2 from '@angular/common';
2
2
  import { DOCUMENT, CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { forwardRef, EventEmitter, Component, ChangeDetectionStrategy, ViewEncapsulation, Inject, Input, Output, ViewChild, ContentChildren, NgModule } from '@angular/core';
4
+ import { forwardRef, EventEmitter, signal, computed, Component, ChangeDetectionStrategy, ViewEncapsulation, Inject, Input, Output, ViewChild, ContentChildren, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import * as i1 from 'primeng/api';
7
- import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api';
7
+ import { PrimeTemplate, SharedModule } from 'primeng/api';
8
8
  import * as i7 from 'primeng/autofocus';
9
9
  import { AutoFocusModule } from 'primeng/autofocus';
10
10
  import * as i4 from 'primeng/button';
@@ -17,7 +17,7 @@ import * as i5 from 'primeng/ripple';
17
17
  import { RippleModule } from 'primeng/ripple';
18
18
  import * as i6 from 'primeng/scroller';
19
19
  import { ScrollerModule } from 'primeng/scroller';
20
- import { UniqueComponentId, ObjectUtils } from 'primeng/utils';
20
+ import { ObjectUtils, UniqueComponentId } from 'primeng/utils';
21
21
  import { TimesCircleIcon } from 'primeng/icons/timescircle';
22
22
  import { SpinnerIcon } from 'primeng/icons/spinner';
23
23
  import { TimesIcon } from 'primeng/icons/times';
@@ -37,7 +37,6 @@ class AutoComplete {
37
37
  el;
38
38
  renderer;
39
39
  cd;
40
- differs;
41
40
  config;
42
41
  overlayService;
43
42
  zone;
@@ -166,24 +165,16 @@ class AutoComplete {
166
165
  * @group Props
167
166
  */
168
167
  type = 'text';
169
- /* @deprecated */
170
- _autoZIndex;
171
- get autoZIndex() {
172
- return this._autoZIndex;
173
- }
174
- set autoZIndex(val) {
175
- this._autoZIndex = val;
176
- console.warn('The autoZIndex property is deprecated since v14.2.0, use overlayOptions property instead.');
177
- }
178
- /* @deprecated */
179
- _baseZIndex;
180
- get baseZIndex() {
181
- return this._baseZIndex;
182
- }
183
- set baseZIndex(val) {
184
- this._baseZIndex = val;
185
- console.warn('The baseZIndex property is deprecated since v14.2.0, use overlayOptions property instead.');
186
- }
168
+ /**
169
+ * Whether to automatically manage layering.
170
+ * @group Props
171
+ */
172
+ autoZIndex = true;
173
+ /**
174
+ * Base zIndex value to use in layering.
175
+ * @group Props
176
+ */
177
+ baseZIndex = 0;
187
178
  /**
188
179
  * Defines a string that labels the input for accessibility.
189
180
  * @group Props
@@ -227,6 +218,7 @@ class AutoComplete {
227
218
  /**
228
219
  * Field of a suggested object to resolve and display.
229
220
  * @group Props
221
+ * @deprecated use optionLabel property instead
230
222
  */
231
223
  field;
232
224
  /**
@@ -288,12 +280,12 @@ class AutoComplete {
288
280
  * Name of the options field of an option group.
289
281
  * @group Props
290
282
  */
291
- optionGroupChildren;
283
+ optionGroupChildren = 'items';
292
284
  /**
293
285
  * Name of the label field of an option group.
294
286
  * @group Props
295
287
  */
296
- optionGroupLabel;
288
+ optionGroupLabel = 'label';
297
289
  /**
298
290
  * Options for the overlay element.
299
291
  * @group Props
@@ -304,10 +296,10 @@ class AutoComplete {
304
296
  * @group Props
305
297
  */
306
298
  get suggestions() {
307
- return this._suggestions;
299
+ return this._suggestions();
308
300
  }
309
301
  set suggestions(value) {
310
- this._suggestions = value;
302
+ this._suggestions.set(value);
311
303
  this.handleSuggestionsChange();
312
304
  }
313
305
  /**
@@ -322,6 +314,59 @@ class AutoComplete {
322
314
  this._itemSize = val;
323
315
  console.warn('The itemSize property is deprecated, use virtualScrollItemSize property instead.');
324
316
  }
317
+ /**
318
+ * Property name or getter function to use as the label of an option.
319
+ * @group Props
320
+ */
321
+ optionLabel;
322
+ /**
323
+ * Unique identifier of the component.
324
+ * @group Props
325
+ */
326
+ id;
327
+ /**
328
+ * Text to display when the search is active. Defaults to global value in i18n translation configuration.
329
+ * @group Props
330
+ * @defaultValue '{0} results are available'
331
+ */
332
+ searchMessage;
333
+ /**
334
+ * Text to display when filtering does not return any results. Defaults to global value in i18n translation configuration.
335
+ * @group Props
336
+ * @defaultValue 'No selected item'
337
+ */
338
+ emptySelectionMessage;
339
+ /**
340
+ * Text to be displayed in hidden accessible field when options are selected. Defaults to global value in i18n translation configuration.
341
+ * @group Props
342
+ * @defaultValue '{0} items selected'
343
+ */
344
+ selectionMessage;
345
+ /**
346
+ * Whether to focus on the first visible or selected element when the overlay panel is shown.
347
+ * @group Props
348
+ */
349
+ autoOptionFocus = true;
350
+ /**
351
+ * When enabled, the focused option is selected.
352
+ * @group Props
353
+ */
354
+ selectOnFocus;
355
+ /**
356
+ * Locale to use in searching. The default locale is the host environment's current locale.
357
+ * @group Props
358
+ */
359
+ searchLocale;
360
+ /**
361
+ * Property name or getter function to use as the disabled flag of an option, defaults to false when not defined.
362
+ * @group Props
363
+ */
364
+ optionDisabled;
365
+ /**
366
+ * When enabled, the hovered option will be focused.
367
+ * @group Props
368
+ */
369
+ focusOnHover;
325
370
  /**
326
371
  * Callback to invoke to search for suggestions.
327
372
  * @param {AutoCompleteCompleteEvent} event - Custom complete event.
@@ -330,13 +375,13 @@ class AutoComplete {
330
375
  completeMethod = new EventEmitter();
331
376
  /**
332
377
  * Callback to invoke when a suggestion is selected.
333
- * @param {*} value - selected value.
378
+ * @param {AutoCompleteOnSelectEvent} event - custom select event.
334
379
  * @group Emits
335
380
  */
336
381
  onSelect = new EventEmitter();
337
382
  /**
338
383
  * Callback to invoke when a selected value is removed.
339
- * @param {*} value - removed value.
384
+ * @param {AutoCompleteUnselectEvent} event - custom unselect event.
340
385
  * @group Emits
341
386
  */
342
387
  onUnselect = new EventEmitter();
@@ -411,40 +456,112 @@ class AutoComplete {
411
456
  clearIconTemplate;
412
457
  dropdownIconTemplate;
413
458
  value;
414
- _suggestions;
459
+ _suggestions = signal(null);
415
460
  onModelChange = () => { };
416
461
  onModelTouched = () => { };
417
462
  timeout;
418
- overlayVisible = false;
463
+ overlayVisible;
419
464
  suggestionsUpdated;
420
465
  highlightOption;
421
466
  highlightOptionChanged;
422
- focus = false;
467
+ focused = false;
423
468
  filled;
424
- inputClick;
425
- inputKeyDown;
426
- noResults;
427
- differ;
428
- inputFieldValue = null;
429
469
  loading;
430
470
  scrollHandler;
431
- documentResizeListener;
432
- forceSelectionUpdateModelTimeout;
433
471
  listId;
434
- itemClicked;
435
- inputValue = null;
436
- isSearching = false;
437
- constructor(document, el, renderer, cd, differs, config, overlayService, zone) {
472
+ searchTimeout;
473
+ dirty = false;
474
+ modelValue = signal(null);
475
+ focusedMultipleOptionIndex = signal(-1);
476
+ focusedOptionIndex = signal(-1);
477
+ visibleOptions = computed(() => {
478
+ return this.group ? this.flatOptions(this._suggestions()) : this._suggestions() || [];
479
+ });
480
+ inputValue = computed(() => {
481
+ const modelValue = this.modelValue();
482
+ this.filled = ObjectUtils.isNotEmpty(this.modelValue());
483
+ if (modelValue) {
484
+ if (typeof modelValue === 'object') {
485
+ const label = this.getOptionLabel(modelValue);
486
+ return label != null ? label : modelValue;
487
+ }
488
+ else {
489
+ return modelValue;
490
+ }
491
+ }
492
+ else {
493
+ return '';
494
+ }
495
+ });
496
+ get focusedMultipleOptionId() {
497
+ return this.focusedMultipleOptionIndex() !== -1 ? `${this.id}_multiple_option_${this.focusedMultipleOptionIndex()}` : null;
498
+ }
499
+ get focusedOptionId() {
500
+ return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
501
+ }
502
+ get containerClass() {
503
+ return {
504
+ 'p-autocomplete p-component p-inputwrapper': true,
505
+ 'p-disabled': this.disabled,
506
+ 'p-focus': this.focused,
507
+ 'p-autocomplete-dd': this.dropdown,
508
+ 'p-autocomplete-multiple': this.multiple,
509
+ 'p-inputwrapper-filled': this.modelValue() || ObjectUtils.isNotEmpty(this.inputValue),
510
+ 'p-inputwrapper-focus': this.focused,
511
+ 'p-overlay-open': this.overlayVisible
512
+ };
513
+ }
514
+ get multiContainerClass() {
515
+ return 'p-autocomplete-multiple-container p-component p-inputtext';
516
+ }
517
+ get panelClass() {
518
+ return {
519
+ 'p-autocomplete-panel p-component': true,
520
+ 'p-input-filled': this.config.inputStyle === 'filled',
521
+ 'p-ripple-disabled': this.config.ripple === false
522
+ };
523
+ }
524
+ get inputClass() {
525
+ return {
526
+ 'p-autocomplete-input p-inputtext p-component': !this.multiple,
527
+ 'p-autocomplete-dd-input': this.dropdown
528
+ };
529
+ }
530
+ get searchResultMessageText() {
531
+ return ObjectUtils.isNotEmpty(this.visibleOptions()) && this.overlayVisible ? this.searchMessageText.replaceAll('{0}', this.visibleOptions().length) : this.emptySearchMessageText;
532
+ }
533
+ get searchMessageText() {
534
+ return this.searchMessage || this.config.translation.searchMessage || '';
535
+ }
536
+ get emptySearchMessageText() {
537
+ return this.emptyMessage || this.config.translation.emptySearchMessage || '';
538
+ }
539
+ get selectionMessageText() {
540
+ return this.selectionMessage || this.config.translation.selectionMessage || '';
541
+ }
542
+ get emptySelectionMessageText() {
543
+ return this.emptySelectionMessage || this.config.translation.emptySelectionMessage || '';
544
+ }
545
+ get selectedMessageText() {
546
+ return this.hasSelectedOption() ? this.selectionMessageText.replaceAll('{0}', this.multiple ? this.modelValue().length : '1') : this.emptySelectionMessageText;
547
+ }
548
+ get ariaSetSize() {
549
+ return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;
550
+ }
551
+ get virtualScrollerDisabled() {
552
+ return !this.virtualScroll;
553
+ }
554
+ constructor(document, el, renderer, cd, config, overlayService, zone) {
438
555
  this.document = document;
439
556
  this.el = el;
440
557
  this.renderer = renderer;
441
558
  this.cd = cd;
442
- this.differs = differs;
443
559
  this.config = config;
444
560
  this.overlayService = overlayService;
445
561
  this.zone = zone;
446
- this.differ = differs.find([]).create(undefined);
447
- this.listId = UniqueComponentId() + '_list';
562
+ }
563
+ ngOnInit() {
564
+ this.id = this.id || UniqueComponentId();
448
565
  }
449
566
  ngAfterViewChecked() {
450
567
  //Use timeouts as since Angular 4.2, AfterViewChecked is broken and not called after panel is updated
@@ -458,44 +575,6 @@ class AutoComplete {
458
575
  this.suggestionsUpdated = false;
459
576
  });
460
577
  }
461
- if (this.highlightOptionChanged) {
462
- this.zone.runOutsideAngular(() => {
463
- setTimeout(() => {
464
- if (this.overlayViewChild && this.itemsWrapper) {
465
- let listItem = DomHandler.findSingle(this.overlayViewChild.overlayViewChild.nativeElement, 'li.p-highlight');
466
- if (listItem) {
467
- DomHandler.scrollInView(this.itemsWrapper, listItem);
468
- }
469
- }
470
- }, 1);
471
- this.highlightOptionChanged = false;
472
- });
473
- }
474
- }
475
- handleSuggestionsChange() {
476
- if (this._suggestions != null && this.loading) {
477
- this.highlightOption = null;
478
- if (this._suggestions.length) {
479
- this.noResults = false;
480
- this.show();
481
- this.suggestionsUpdated = true;
482
- if (this.autoHighlight) {
483
- this.highlightOption = this._suggestions[0];
484
- }
485
- }
486
- else {
487
- this.noResults = true;
488
- if (this.showEmptyMessage) {
489
- this.show();
490
- this.suggestionsUpdated = true;
491
- }
492
- else {
493
- this.hide();
494
- }
495
- }
496
- this.loading = false;
497
- this.isSearching = false;
498
- }
499
578
  }
500
579
  ngAfterContentInit() {
501
580
  this.templates.forEach((item) => {
@@ -539,518 +618,664 @@ class AutoComplete {
539
618
  }
540
619
  });
541
620
  }
542
- writeValue(value) {
543
- this.value = value;
544
- this.filled = this.value && this.value.length ? true : false;
545
- this.updateInputField();
546
- this.cd.markForCheck();
621
+ handleSuggestionsChange() {
622
+ if (this.loading) {
623
+ this._suggestions() ? this.show() : !!this.emptyTemplate ? this.show() : this.hide();
624
+ const focusedOptionIndex = this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
625
+ this.focusedOptionIndex.set(focusedOptionIndex);
626
+ this.suggestionsUpdated = true;
627
+ this.loading = false;
628
+ this.cd.markForCheck();
629
+ }
547
630
  }
548
- getOptionGroupChildren(optionGroup) {
549
- return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
631
+ flatOptions(options) {
632
+ return (options || []).reduce((result, option, index) => {
633
+ result.push({ optionGroup: option, group: true, index });
634
+ const optionGroupChildren = this.getOptionGroupChildren(option);
635
+ optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));
636
+ return result;
637
+ }, []);
550
638
  }
551
- getOptionGroupLabel(optionGroup) {
552
- return this.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel) : optionGroup.label != undefined ? optionGroup.label : optionGroup;
639
+ isOptionGroup(option) {
640
+ return this.optionGroupLabel && option.optionGroup && option.group;
553
641
  }
554
- registerOnChange(fn) {
555
- this.onModelChange = fn;
642
+ findFirstOptionIndex() {
643
+ return this.visibleOptions().findIndex((option) => this.isValidOption(option));
556
644
  }
557
- registerOnTouched(fn) {
558
- this.onModelTouched = fn;
645
+ findLastOptionIndex() {
646
+ return ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));
559
647
  }
560
- setDisabledState(val) {
561
- this.disabled = val;
562
- this.cd.markForCheck();
648
+ findFirstFocusedOptionIndex() {
649
+ const selectedIndex = this.findSelectedOptionIndex();
650
+ return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
563
651
  }
564
- onInput(event) {
565
- // When an input element with a placeholder is clicked, the onInput event is invoked in IE.
566
- if (!this.inputKeyDown && DomHandler.isIE()) {
652
+ findLastFocusedOptionIndex() {
653
+ const selectedIndex = this.findSelectedOptionIndex();
654
+ return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
655
+ }
656
+ findSelectedOptionIndex() {
657
+ return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;
658
+ }
659
+ findNextOptionIndex(index) {
660
+ const matchedOptionIndex = index < this.visibleOptions().length - 1
661
+ ? this.visibleOptions()
662
+ .slice(index + 1)
663
+ .findIndex((option) => this.isValidOption(option))
664
+ : -1;
665
+ return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;
666
+ }
667
+ findPrevOptionIndex(index) {
668
+ const matchedOptionIndex = index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;
669
+ return matchedOptionIndex > -1 ? matchedOptionIndex : index;
670
+ }
671
+ isValidSelectedOption(option) {
672
+ return this.isValidOption(option) && this.isSelected(option);
673
+ }
674
+ isValidOption(option) {
675
+ return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));
676
+ }
677
+ isOptionDisabled(option) {
678
+ return this.optionDisabled ? ObjectUtils.resolveFieldData(option, this.optionDisabled) : false;
679
+ }
680
+ isSelected(option) {
681
+ return ObjectUtils.equals(this.modelValue(), this.getOptionValue(option), this.equalityKey());
682
+ }
683
+ isOptionMatched(option, value) {
684
+ return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.searchLocale) === value.toLocaleLowerCase(this.searchLocale);
685
+ }
686
+ isInputClicked(event) {
687
+ if (this.multiple)
688
+ return event.target === this.multiContainerEL.nativeElement || this.multiContainerEL.nativeElement.contains(event.target);
689
+ else
690
+ return event.target === this.inputEL.nativeElement;
691
+ }
692
+ isDropdownClicked(event) {
693
+ return this.dropdownButton?.nativeElement ? event.target === this.dropdownButton.nativeElement || this.dropdownButton.nativeElement.contains(event.target) : false;
694
+ }
695
+ equalityKey() {
696
+ return this.dataKey; // TODO: The 'optionValue' properties can be added.
697
+ }
698
+ onContainerClick(event) {
699
+ if (this.disabled || this.loading || this.isInputClicked(event) || this.isDropdownClicked(event)) {
567
700
  return;
568
701
  }
569
- if (this.timeout) {
570
- clearTimeout(this.timeout);
702
+ if (!this.overlayViewChild || !this.overlayViewChild.overlayViewChild.nativeElement.contains(event.target)) {
703
+ DomHandler.focus(this.inputEL.nativeElement);
704
+ }
705
+ }
706
+ handleDropdownClick(event) {
707
+ let query = undefined;
708
+ if (this.overlayVisible) {
709
+ this.hide(true);
571
710
  }
572
- let value = event.target.value;
573
- this.inputValue = value;
574
- if (!this.multiple && !this.forceSelection) {
575
- this.onModelChange(value);
711
+ else {
712
+ DomHandler.focus(this.inputEL.nativeElement);
713
+ query = this.inputEL.nativeElement.value;
714
+ if (this.dropdownMode === 'blank')
715
+ this.search(event, '', 'dropdown');
716
+ else if (this.dropdownMode === 'current')
717
+ this.search(event, query, 'dropdown');
576
718
  }
577
- if (value.length === 0 && !this.multiple) {
578
- this.value = null;
579
- this.hide();
580
- this.onClear.emit(event);
581
- this.onModelChange(value);
719
+ this.onDropdownClick.emit({ originalEvent: event, query });
720
+ }
721
+ onInput(event) {
722
+ if (this.searchTimeout) {
723
+ clearTimeout(this.searchTimeout);
582
724
  }
583
- if (value.length >= this.minLength) {
584
- this.timeout = setTimeout(() => {
585
- this.search(event, value);
586
- }, this.delay);
725
+ let query = event.target.value;
726
+ if (!this.multiple) {
727
+ this.updateModel(query);
587
728
  }
588
- else {
729
+ if (query.length === 0) {
589
730
  this.hide();
731
+ this.onClear.emit();
590
732
  }
591
- this.updateFilledState();
592
- this.inputKeyDown = false;
593
- }
594
- onInputClick(event) {
595
- this.inputClick = true;
596
- }
597
- search(event, query) {
598
- if (!this.isSearching) {
599
- this.isSearching = true;
600
- this.loading = true;
601
- this.completeMethod.emit({
602
- originalEvent: event,
603
- query: query
604
- });
605
- setTimeout(() => {
606
- this.isSearching = false;
607
- }, 100);
733
+ else {
734
+ if (query.length >= this.minLength) {
735
+ this.focusedOptionIndex.set(-1);
736
+ this.searchTimeout = setTimeout(() => {
737
+ this.search(event, query, 'input');
738
+ }, this.delay);
739
+ }
740
+ else {
741
+ this.hide();
742
+ }
608
743
  }
609
744
  }
610
- selectItem(option, focus = true) {
611
- if (this.forceSelectionUpdateModelTimeout) {
612
- clearTimeout(this.forceSelectionUpdateModelTimeout);
613
- this.forceSelectionUpdateModelTimeout = null;
614
- }
615
- if (this.multiple) {
616
- this.multiInputEl.nativeElement.value = '';
617
- this.value = this.value || [];
618
- if (!this.isSelected(option) || !this.unique) {
619
- this.value = [...this.value, option];
620
- this.onModelChange(this.value);
745
+ onInputChange(event) {
746
+ if (this.forceSelection) {
747
+ let valid = false;
748
+ if (this.visibleOptions()) {
749
+ const matchedValue = this.visibleOptions().find((option) => this.isOptionMatched(option, this.inputEL.nativeElement.value || ''));
750
+ if (matchedValue !== undefined) {
751
+ valid = true;
752
+ !this.isSelected(matchedValue) && this.onOptionSelect(event, matchedValue);
753
+ }
754
+ }
755
+ if (!valid) {
756
+ this.inputEL.nativeElement.value = '';
757
+ !this.multiple && this.updateModel(null);
621
758
  }
622
759
  }
623
- else {
624
- this.inputEL.nativeElement.value = this.resolveFieldData(option);
625
- this.value = option;
626
- this.onModelChange(this.value);
760
+ }
761
+ onInputFocus(event) {
762
+ if (this.disabled) {
763
+ // For ScreenReaders
764
+ return;
627
765
  }
628
- this.onSelect.emit(option);
629
- this.updateFilledState();
630
- if (focus) {
631
- this.itemClicked = true;
632
- this.focusInput();
766
+ if (!this.dirty && this.completeOnFocus) {
767
+ this.search(event, event.target.value, 'focus');
633
768
  }
634
- this.hide();
769
+ this.dirty = true;
770
+ this.focused = true;
771
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
772
+ this.focusedOptionIndex.set(focusedOptionIndex);
773
+ this.overlayVisible && this.scrollInView(this.focusedOptionIndex());
774
+ this.onFocus.emit(event);
635
775
  }
636
- show(event) {
637
- if (this.multiInputEl || this.inputEL) {
638
- let hasFocus = this.multiple ? this.multiInputEl?.nativeElement.ownerDocument.activeElement == this.multiInputEl?.nativeElement : this.inputEL?.nativeElement.ownerDocument.activeElement == this.inputEL?.nativeElement;
639
- if (!this.overlayVisible && hasFocus) {
640
- this.overlayVisible = true;
641
- }
776
+ onMultipleContainerFocus(event) {
777
+ if (this.disabled) {
778
+ // For ScreenReaders
779
+ return;
642
780
  }
643
- this.onShow.emit(event);
644
- this.cd.markForCheck();
781
+ this.focused = true;
645
782
  }
646
- clear() {
647
- this.value = null;
648
- this.inputValue = null;
649
- if (this.multiple) {
650
- this.multiInputEl.nativeElement.value = '';
783
+ onMultipleContainerBlur(event) {
784
+ this.focusedMultipleOptionIndex.set(-1);
785
+ this.focused = false;
786
+ }
787
+ onMultipleContainerKeyDown(event) {
788
+ if (this.disabled) {
789
+ event.preventDefault();
790
+ return;
651
791
  }
652
- else {
653
- this.inputValue = null;
654
- this.inputEL.nativeElement.value = '';
792
+ switch (event.code) {
793
+ case 'ArrowLeft':
794
+ this.onArrowLeftKeyOnMultiple(event);
795
+ break;
796
+ case 'ArrowRight':
797
+ this.onArrowRightKeyOnMultiple(event);
798
+ break;
799
+ case 'Backspace':
800
+ this.onBackspaceKeyOnMultiple(event);
801
+ break;
802
+ default:
803
+ break;
655
804
  }
656
- this.updateFilledState();
657
- this.onModelChange(this.value);
658
- this.onClear.emit();
659
805
  }
660
- onOverlayAnimationStart(event) {
661
- if (event.toState === 'visible') {
662
- this.itemsWrapper = DomHandler.findSingle(this.overlayViewChild.overlayViewChild?.nativeElement, this.virtualScroll ? '.p-scroller' : '.p-autocomplete-panel');
663
- this.virtualScroll && this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
664
- }
806
+ onInputBlur(event) {
807
+ this.dirty = false;
808
+ this.focused = false;
809
+ this.focusedOptionIndex.set(-1);
810
+ this.onModelTouched();
811
+ this.onBlur.emit(event);
665
812
  }
666
- resolveFieldData(value) {
667
- let data = this.field ? ObjectUtils.resolveFieldData(value, this.field) : value;
668
- return data !== (null || undefined) ? data : '';
813
+ onInputPaste(event) {
814
+ this.onKeyDown(event);
669
815
  }
670
- hide(event) {
671
- this.overlayVisible = false;
672
- this.onHide.emit(event);
673
- this.cd.markForCheck();
816
+ onInputKeyUp(event) {
817
+ this.onKeyUp.emit(event);
674
818
  }
675
- handleDropdownClick(event) {
819
+ onKeyDown(event) {
820
+ if (this.disabled) {
821
+ event.preventDefault();
822
+ return;
823
+ }
824
+ switch (event.code) {
825
+ case 'ArrowDown':
826
+ this.onArrowDownKey(event);
827
+ break;
828
+ case 'ArrowUp':
829
+ this.onArrowUpKey(event);
830
+ break;
831
+ case 'ArrowLeft':
832
+ this.onArrowLeftKey(event);
833
+ break;
834
+ case 'ArrowRight':
835
+ this.onArrowRightKey(event);
836
+ break;
837
+ case 'Home':
838
+ this.onHomeKey(event);
839
+ break;
840
+ case 'End':
841
+ this.onEndKey(event);
842
+ break;
843
+ case 'PageDown':
844
+ this.onPageDownKey(event);
845
+ break;
846
+ case 'PageUp':
847
+ this.onPageUpKey(event);
848
+ break;
849
+ case 'Enter':
850
+ case 'NumpadEnter':
851
+ this.onEnterKey(event);
852
+ break;
853
+ case 'Escape':
854
+ this.onEscapeKey(event);
855
+ break;
856
+ case 'Tab':
857
+ this.onTabKey(event);
858
+ break;
859
+ case 'Backspace':
860
+ this.onBackspaceKey(event);
861
+ break;
862
+ case 'ShiftLeft':
863
+ case 'ShiftRight':
864
+ //NOOP
865
+ break;
866
+ default:
867
+ break;
868
+ }
869
+ }
870
+ onArrowDownKey(event) {
676
871
  if (!this.overlayVisible) {
677
- this.focusInput();
678
- let queryValue = this.multiple ? this.multiInputEl.nativeElement.value : this.inputEL.nativeElement.value;
679
- if (this.dropdownMode === 'blank') {
680
- this.onDropdownClick.emit({
681
- originalEvent: event,
682
- query: ''
683
- });
684
- this.search(event, '');
685
- }
686
- else if (this.dropdownMode === 'current') {
687
- this.onDropdownClick.emit({
688
- originalEvent: event,
689
- query: queryValue
690
- });
691
- this.search(event, queryValue);
872
+ return;
873
+ }
874
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex()) : this.findFirstFocusedOptionIndex();
875
+ this.changeFocusedOptionIndex(event, optionIndex);
876
+ event.preventDefault();
877
+ }
878
+ onArrowUpKey(event) {
879
+ if (!this.overlayVisible) {
880
+ return;
881
+ }
882
+ if (event.altKey) {
883
+ if (this.focusedOptionIndex() !== -1) {
884
+ this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
692
885
  }
886
+ this.overlayVisible && this.hide();
887
+ event.preventDefault();
693
888
  }
694
889
  else {
695
- this.hide(event);
890
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex()) : this.findLastFocusedOptionIndex();
891
+ this.changeFocusedOptionIndex(event, optionIndex);
892
+ event.preventDefault();
696
893
  }
697
894
  }
698
- focusInput() {
699
- if (this.multiple)
700
- this.multiInputEl.nativeElement.focus();
701
- else
702
- this.inputEL?.nativeElement.focus();
895
+ onArrowLeftKey(event) {
896
+ const target = event.currentTarget;
897
+ this.focusedOptionIndex.set(-1);
898
+ if (this.multiple) {
899
+ if (ObjectUtils.isEmpty(target.value) && this.hasSelectedOption()) {
900
+ DomHandler.focus(this.multiContainerEL.nativeElement);
901
+ this.focusedMultipleOptionIndex.set(this.modelValue().length);
902
+ }
903
+ else {
904
+ event.stopPropagation(); // To prevent onArrowLeftKeyOnMultiple method
905
+ }
906
+ }
703
907
  }
704
- get emptyMessageLabel() {
705
- return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
908
+ onArrowRightKey(event) {
909
+ this.focusedOptionIndex.set(-1);
910
+ this.multiple && event.stopPropagation(); // To prevent onArrowRightKeyOnMultiple method
706
911
  }
707
- removeItem(item) {
708
- let itemIndex = DomHandler.index(item);
709
- let removedValue = this.value[itemIndex];
710
- this.value = this.value.filter((val, i) => i != itemIndex);
711
- this.onModelChange(this.value);
712
- this.updateFilledState();
713
- this.onUnselect.emit(removedValue);
912
+ onHomeKey(event) {
913
+ const { currentTarget } = event;
914
+ const len = currentTarget.value.length;
915
+ currentTarget.setSelectionRange(0, event.shiftKey ? len : 0);
916
+ this.focusedOptionIndex.set(-1);
917
+ event.preventDefault();
714
918
  }
715
- onKeydown(event) {
716
- if (this.overlayVisible) {
717
- switch (event.which) {
718
- //down
719
- case 40:
720
- if (this.group) {
721
- let highlightItemIndex = this.findOptionGroupIndex(this.highlightOption, this.suggestions);
722
- if (highlightItemIndex !== -1) {
723
- let nextItemIndex = highlightItemIndex.itemIndex + 1;
724
- if (nextItemIndex < this.getOptionGroupChildren(this.suggestions[highlightItemIndex.groupIndex]).length) {
725
- this.highlightOption = this.getOptionGroupChildren(this.suggestions[highlightItemIndex.groupIndex])[nextItemIndex];
726
- this.highlightOptionChanged = true;
727
- }
728
- else if (this.suggestions[highlightItemIndex.groupIndex + 1]) {
729
- this.highlightOption = this.getOptionGroupChildren(this.suggestions[highlightItemIndex.groupIndex + 1])[0];
730
- this.highlightOptionChanged = true;
731
- }
732
- }
733
- else {
734
- this.highlightOption = this.getOptionGroupChildren(this.suggestions[0])[0];
735
- }
736
- }
737
- else {
738
- let highlightItemIndex = this.findOptionIndex(this.highlightOption, this.suggestions);
739
- if (highlightItemIndex != -1) {
740
- var nextItemIndex = highlightItemIndex + 1;
741
- if (nextItemIndex != this.suggestions.length) {
742
- this.highlightOption = this.suggestions[nextItemIndex];
743
- this.highlightOptionChanged = true;
744
- }
745
- }
746
- else {
747
- this.highlightOption = this.suggestions[0];
748
- }
749
- }
750
- event.preventDefault();
751
- break;
752
- //up
753
- case 38:
754
- if (this.group) {
755
- let highlightItemIndex = this.findOptionGroupIndex(this.highlightOption, this.suggestions);
756
- if (highlightItemIndex !== -1) {
757
- let prevItemIndex = highlightItemIndex.itemIndex - 1;
758
- if (prevItemIndex >= 0) {
759
- this.highlightOption = this.getOptionGroupChildren(this.suggestions[highlightItemIndex.groupIndex])[prevItemIndex];
760
- this.highlightOptionChanged = true;
761
- }
762
- else if (prevItemIndex < 0) {
763
- let prevGroup = this.suggestions[highlightItemIndex.groupIndex - 1];
764
- if (prevGroup) {
765
- this.highlightOption = this.getOptionGroupChildren(prevGroup)[this.getOptionGroupChildren(prevGroup).length - 1];
766
- this.highlightOptionChanged = true;
767
- }
768
- }
769
- }
770
- }
771
- else {
772
- let highlightItemIndex = this.findOptionIndex(this.highlightOption, this.suggestions);
773
- if (highlightItemIndex > 0) {
774
- let prevItemIndex = highlightItemIndex - 1;
775
- this.highlightOption = this.suggestions[prevItemIndex];
776
- this.highlightOptionChanged = true;
777
- }
778
- }
779
- event.preventDefault();
780
- break;
781
- //enter
782
- case 13:
783
- if (this.highlightOption) {
784
- this.selectItem(this.highlightOption);
785
- this.hide();
786
- }
787
- event.preventDefault();
788
- break;
789
- //escape
790
- case 27:
791
- this.hide();
792
- event.preventDefault();
793
- break;
794
- //tab
795
- case 9:
796
- if (this.highlightOption) {
797
- this.selectItem(this.highlightOption);
798
- }
799
- this.hide();
800
- break;
801
- }
919
+ onEndKey(event) {
920
+ const { currentTarget } = event;
921
+ const len = currentTarget.value.length;
922
+ currentTarget.setSelectionRange(event.shiftKey ? 0 : len, len);
923
+ this.focusedOptionIndex.set(-1);
924
+ event.preventDefault();
925
+ }
926
+ onPageDownKey(event) {
927
+ this.scrollInView(this.visibleOptions().length - 1);
928
+ event.preventDefault();
929
+ }
930
+ onPageUpKey(event) {
931
+ this.scrollInView(0);
932
+ event.preventDefault();
933
+ }
934
+ onEnterKey(event) {
935
+ if (!this.overlayVisible) {
936
+ this.onArrowDownKey(event);
802
937
  }
803
938
  else {
804
- if (event.which === 40 && this.suggestions) {
805
- this.search(event, event.target.value);
806
- }
807
- else if (event.ctrlKey && event.key === 'z' && !this.multiple) {
808
- this.inputEL.nativeElement.value = this.resolveFieldData(null);
809
- this.value = '';
810
- this.onModelChange(this.value);
939
+ if (this.focusedOptionIndex() !== -1) {
940
+ this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
811
941
  }
812
- else if (event.ctrlKey && event.key === 'z' && this.multiple) {
813
- this.value.pop();
814
- this.onModelChange(this.value);
815
- this.updateFilledState();
942
+ this.hide();
943
+ }
944
+ event.preventDefault();
945
+ }
946
+ onEscapeKey(event) {
947
+ this.overlayVisible && this.hide(true);
948
+ event.preventDefault();
949
+ }
950
+ onTabKey(event) {
951
+ if (this.focusedOptionIndex() !== -1) {
952
+ this.onOptionSelect(event, this.visibleOptions()[this.focusedOptionIndex()]);
953
+ }
954
+ this.overlayVisible && this.hide();
955
+ }
956
+ onBackspaceKey(event) {
957
+ if (this.multiple) {
958
+ if (ObjectUtils.isNotEmpty(this.modelValue()) && !this.inputEL.nativeElement.value) {
959
+ const removedValue = this.modelValue()[this.modelValue().length - 1];
960
+ const newValue = this.modelValue().slice(0, -1);
961
+ this.updateModel(newValue);
962
+ this.onUnselect.emit({ originalEvent: event, value: removedValue });
816
963
  }
964
+ event.stopPropagation(); // To prevent onBackspaceKeyOnMultiple method
965
+ }
966
+ }
967
+ onArrowLeftKeyOnMultiple(event) {
968
+ const optionIndex = this.focusedMultipleOptionIndex() < 1 ? 0 : this.focusedMultipleOptionIndex() - 1;
969
+ this.focusedMultipleOptionIndex.set(optionIndex);
970
+ }
971
+ onArrowRightKeyOnMultiple(event) {
972
+ let optionIndex = this.focusedMultipleOptionIndex();
973
+ optionIndex++;
974
+ this.focusedMultipleOptionIndex.set(optionIndex);
975
+ if (optionIndex > this.modelValue().length - 1) {
976
+ this.focusedMultipleOptionIndex.set(-1);
977
+ DomHandler.focus(this.inputEL.nativeElement);
978
+ }
979
+ }
980
+ onBackspaceKeyOnMultiple(event) {
981
+ if (this.focusedMultipleOptionIndex() !== -1) {
982
+ this.removeOption(event, this.focusedMultipleOptionIndex());
817
983
  }
984
+ }
985
+ onOptionSelect(event, option, isHide = true) {
986
+ const value = this.getOptionValue(option);
818
987
  if (this.multiple) {
819
- switch (event.which) {
820
- //backspace
821
- case 8:
822
- if (this.value && this.value.length && !this.multiInputEl?.nativeElement.value) {
823
- this.value = [...this.value];
824
- const removedValue = this.value.pop();
825
- this.onModelChange(this.value);
826
- this.updateFilledState();
827
- this.onUnselect.emit(removedValue);
828
- }
829
- break;
988
+ this.inputEL.nativeElement.value = '';
989
+ if (!this.isSelected(option)) {
990
+ this.updateModel([...(this.modelValue() || []), value]);
830
991
  }
831
992
  }
832
- this.inputKeyDown = true;
993
+ else {
994
+ this.updateModel(value);
995
+ }
996
+ this.onSelect.emit({ originalEvent: event, value: option });
997
+ isHide && this.hide(true);
833
998
  }
834
- onKeyup(event) {
835
- this.onKeyUp.emit(event);
999
+ onOptionMouseEnter(event, index) {
1000
+ if (this.focusOnHover) {
1001
+ this.changeFocusedOptionIndex(event, index);
1002
+ }
836
1003
  }
837
- onInputFocus(event) {
838
- if (!this.itemClicked && this.completeOnFocus) {
839
- let queryValue = this.multiple ? this.multiInputEl?.nativeElement.value : this.inputEL?.nativeElement.value;
840
- this.search(event, queryValue);
1004
+ search(event, query, source) {
1005
+ //allow empty string but not undefined or null
1006
+ if (query === undefined || query === null) {
1007
+ return;
841
1008
  }
842
- this.focus = true;
843
- this.onFocus.emit(event);
844
- this.itemClicked = false;
1009
+ //do not search blank values on input change
1010
+ if (source === 'input' && query.trim().length === 0) {
1011
+ return;
1012
+ }
1013
+ this.loading = true;
1014
+ this.completeMethod.emit({ originalEvent: event, query });
845
1015
  }
846
- onInputBlur(event) {
847
- this.focus = false;
848
- this.onModelTouched();
849
- this.onBlur.emit(event);
1016
+ removeOption(event, index) {
1017
+ const removedOption = this.modelValue()[index];
1018
+ const value = this.modelValue()
1019
+ .filter((_, i) => i !== index)
1020
+ .map((option) => this.getOptionValue(option));
1021
+ this.updateModel(value);
1022
+ this.onUnselect.emit({ originalEvent: event, value: removedOption });
1023
+ DomHandler.focus(this.inputEL.nativeElement);
850
1024
  }
851
- onInputChange(event) {
852
- if (this.forceSelection) {
853
- let valid = false;
854
- const target = event.target;
855
- let inputValue = target.value.trim();
856
- if (this.suggestions) {
857
- let suggestions = [...this.suggestions];
858
- if (this.group) {
859
- let groupedSuggestions = this.suggestions.filter((s) => s[this.optionGroupChildren]).flatMap((s) => s[this.optionGroupChildren]);
860
- suggestions = suggestions.concat(groupedSuggestions);
861
- }
862
- for (let suggestion of suggestions) {
863
- let itemValue = this.field ? ObjectUtils.resolveFieldData(suggestion, this.field) : suggestion;
864
- if (itemValue && inputValue.toLowerCase() === itemValue.toLowerCase().trim()) {
865
- valid = true;
866
- this.forceSelectionUpdateModelTimeout = setTimeout(() => {
867
- this.selectItem(suggestion, false);
868
- }, 250);
869
- break;
870
- }
871
- }
1025
+ updateModel(value) {
1026
+ this.value = value;
1027
+ this.modelValue.set(value);
1028
+ this.onModelChange(value);
1029
+ this.updateInputValue();
1030
+ this.cd.markForCheck();
1031
+ }
1032
+ updateInputValue() {
1033
+ if (this.value && this.inputEL && this.inputEL.nativeElement) {
1034
+ if (!this.multiple) {
1035
+ this.inputEL.nativeElement.value = this.inputValue();
872
1036
  }
873
- if (!valid) {
874
- if (this.multiple) {
875
- this.multiInputEl.nativeElement.value = '';
876
- }
877
- else {
878
- this.value = null;
879
- this.inputEL.nativeElement.value = '';
880
- }
881
- this.onClear.emit(event);
882
- this.onModelChange(this.value);
883
- this.updateFilledState();
1037
+ else {
1038
+ this.inputEL.nativeElement.value = '';
884
1039
  }
885
1040
  }
886
1041
  }
887
- onInputPaste(event) {
888
- this.onKeydown(event);
889
- }
890
- isSelected(val) {
891
- let selected = false;
892
- if (this.value && this.value.length) {
893
- for (let i = 0; i < this.value.length; i++) {
894
- if (ObjectUtils.equals(this.value[i], val, this.dataKey)) {
895
- selected = true;
896
- break;
897
- }
898
- }
1042
+ autoUpdateModel() {
1043
+ if ((this.selectOnFocus || this.autoHighlight) && this.autoOptionFocus && !this.hasSelectedOption()) {
1044
+ const focusedOptionIndex = this.findFirstFocusedOptionIndex();
1045
+ this.focusedOptionIndex.set(focusedOptionIndex);
1046
+ this.onOptionSelect(null, this.visibleOptions()[this.focusedOptionIndex()], false);
899
1047
  }
900
- return selected;
901
- }
902
- findOptionIndex(option, suggestions) {
903
- let index = -1;
904
- if (suggestions) {
905
- for (let i = 0; i < suggestions.length; i++) {
906
- if (ObjectUtils.equals(option, suggestions[i])) {
907
- index = i;
908
- break;
909
- }
1048
+ }
1049
+ scrollInView(index = -1) {
1050
+ const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
1051
+ if (this.itemsViewChild && this.itemsViewChild.nativeElement) {
1052
+ const element = DomHandler.findSingle(this.itemsViewChild.nativeElement, `li[id="${id}"]`);
1053
+ if (element) {
1054
+ element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'nearest' });
910
1055
  }
911
- }
912
- return index;
913
- }
914
- findOptionGroupIndex(val, opts) {
915
- let groupIndex, itemIndex;
916
- if (opts) {
917
- for (let i = 0; i < opts.length; i++) {
918
- groupIndex = i;
919
- itemIndex = this.findOptionIndex(val, this.getOptionGroupChildren(opts[i]));
920
- if (itemIndex !== -1) {
921
- break;
922
- }
1056
+ else if (!this.virtualScrollerDisabled) {
1057
+ setTimeout(() => {
1058
+ this.virtualScroll && this.scroller?.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex());
1059
+ }, 0);
923
1060
  }
924
1061
  }
925
- if (itemIndex !== -1) {
926
- return { groupIndex: groupIndex, itemIndex: itemIndex };
1062
+ }
1063
+ changeFocusedOptionIndex(event, index) {
1064
+ if (this.focusedOptionIndex() !== index) {
1065
+ this.focusedOptionIndex.set(index);
1066
+ this.scrollInView();
1067
+ if (this.selectOnFocus || this.autoHighlight) {
1068
+ this.onOptionSelect(event, this.visibleOptions()[index], false);
1069
+ }
927
1070
  }
928
- else {
929
- return -1;
1071
+ }
1072
+ show(isFocus = false) {
1073
+ this.dirty = true;
1074
+ this.overlayVisible = true;
1075
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
1076
+ this.focusedOptionIndex.set(focusedOptionIndex);
1077
+ isFocus && DomHandler.focus(this.inputEL.nativeElement);
1078
+ if (isFocus) {
1079
+ DomHandler.focus(this.inputEL.nativeElement);
930
1080
  }
1081
+ this.onShow.emit();
1082
+ this.cd.markForCheck();
931
1083
  }
932
- updateFilledState() {
933
- if (this.multiple)
934
- this.filled = (this.value && this.value.length) || (this.multiInputEl && this.multiInputEl.nativeElement && this.multiInputEl.nativeElement.value != '');
935
- else
936
- this.filled = (this.inputFieldValue && this.inputFieldValue != '') || (this.inputEL && this.inputEL.nativeElement && this.inputEL.nativeElement.value != '');
1084
+ hide(isFocus = false) {
1085
+ const _hide = () => {
1086
+ this.dirty = isFocus;
1087
+ this.overlayVisible = false;
1088
+ this.focusedOptionIndex.set(-1);
1089
+ isFocus && DomHandler.focus(this.inputEL.nativeElement);
1090
+ this.onHide.emit();
1091
+ this.cd.markForCheck();
1092
+ };
1093
+ setTimeout(() => {
1094
+ _hide();
1095
+ }, 0); // For ScreenReaders
937
1096
  }
938
- updateInputField() {
939
- let formattedValue = this.resolveFieldData(this.value);
940
- this.inputFieldValue = formattedValue;
941
- if (this.inputEL && this.inputEL.nativeElement) {
942
- this.inputEL.nativeElement.value = formattedValue;
1097
+ clear() {
1098
+ this.updateModel(null);
1099
+ this.inputEL.nativeElement.value = '';
1100
+ this.onClear.emit();
1101
+ }
1102
+ writeValue(value) {
1103
+ this.value = value;
1104
+ this.filled = this.value && this.value.length ? true : false;
1105
+ this.updateModel(value);
1106
+ this.cd.markForCheck();
1107
+ }
1108
+ hasSelectedOption() {
1109
+ return ObjectUtils.isNotEmpty(this.modelValue());
1110
+ }
1111
+ getAriaPosInset(index) {
1112
+ return ((this.optionGroupLabel
1113
+ ? index -
1114
+ this.visibleOptions()
1115
+ .slice(0, index)
1116
+ .filter((option) => this.isOptionGroup(option)).length
1117
+ : index) + 1);
1118
+ }
1119
+ getOptionLabel(option) {
1120
+ return this.field || this.optionLabel ? ObjectUtils.resolveFieldData(option, this.field || this.optionLabel) : option && option.label != undefined ? option.label : option;
1121
+ }
1122
+ getOptionValue(option) {
1123
+ return option; // TODO: The 'optionValue' properties can be added.
1124
+ }
1125
+ getOptionIndex(index, scrollerOptions) {
1126
+ return this.virtualScrollerDisabled ? index : scrollerOptions && scrollerOptions.getItemOptions(index)['index'];
1127
+ }
1128
+ getOptionGroupLabel(optionGroup) {
1129
+ return this.optionGroupLabel ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupLabel) : optionGroup && optionGroup.label != undefined ? optionGroup.label : optionGroup;
1130
+ }
1131
+ getOptionGroupChildren(optionGroup) {
1132
+ return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
1133
+ }
1134
+ registerOnChange(fn) {
1135
+ this.onModelChange = fn;
1136
+ }
1137
+ registerOnTouched(fn) {
1138
+ this.onModelTouched = fn;
1139
+ }
1140
+ setDisabledState(val) {
1141
+ this.disabled = val;
1142
+ this.cd.markForCheck();
1143
+ }
1144
+ onOverlayAnimationStart(event) {
1145
+ if (event.toState === 'visible') {
1146
+ this.itemsWrapper = DomHandler.findSingle(this.overlayViewChild.overlayViewChild?.nativeElement, this.virtualScroll ? '.p-scroller' : '.p-autocomplete-panel');
1147
+ this.virtualScroll && this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
943
1148
  }
944
- this.updateFilledState();
945
1149
  }
946
1150
  ngOnDestroy() {
947
- if (this.forceSelectionUpdateModelTimeout) {
948
- clearTimeout(this.forceSelectionUpdateModelTimeout);
949
- this.forceSelectionUpdateModelTimeout = null;
950
- }
951
1151
  if (this.scrollHandler) {
952
1152
  this.scrollHandler.destroy();
953
1153
  this.scrollHandler = null;
954
1154
  }
955
1155
  }
956
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: AutoComplete, deps: [{ token: DOCUMENT }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.IterableDiffers }, { token: i1.PrimeNGConfig }, { token: i1.OverlayService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
957
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: AutoComplete, selector: "p-autoComplete", inputs: { minLength: "minLength", delay: "delay", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", inputStyle: "inputStyle", inputId: "inputId", inputStyleClass: "inputStyleClass", placeholder: "placeholder", readonly: "readonly", disabled: "disabled", scrollHeight: "scrollHeight", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", maxlength: "maxlength", name: "name", required: "required", size: "size", appendTo: "appendTo", autoHighlight: "autoHighlight", forceSelection: "forceSelection", type: "type", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", ariaLabel: "ariaLabel", dropdownAriaLabel: "dropdownAriaLabel", ariaLabelledBy: "ariaLabelledBy", dropdownIcon: "dropdownIcon", unique: "unique", group: "group", completeOnFocus: "completeOnFocus", showClear: "showClear", field: "field", dropdown: "dropdown", showEmptyMessage: "showEmptyMessage", dropdownMode: "dropdownMode", multiple: "multiple", tabindex: "tabindex", dataKey: "dataKey", emptyMessage: "emptyMessage", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", autofocus: "autofocus", autocomplete: "autocomplete", optionGroupChildren: "optionGroupChildren", optionGroupLabel: "optionGroupLabel", overlayOptions: "overlayOptions", suggestions: "suggestions", itemSize: "itemSize" }, outputs: { completeMethod: "completeMethod", onSelect: "onSelect", onUnselect: "onUnselect", onFocus: "onFocus", onBlur: "onBlur", onDropdownClick: "onDropdownClick", onClear: "onClear", onKeyUp: "onKeyUp", onShow: "onShow", onHide: "onHide", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "((focus && !disabled) || autofocus) || overlayVisible", "class.p-autocomplete-clearable": "showClear && !disabled" }, classAttribute: "p-element p-inputwrapper" }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerEL", first: true, predicate: ["container"], descendants: true }, { propertyName: "inputEL", first: true, predicate: ["in"], descendants: true }, { propertyName: "multiInputEl", first: true, predicate: ["multiIn"], descendants: true }, { propertyName: "multiContainerEL", first: true, predicate: ["multiContainer"], descendants: true }, { propertyName: "dropdownButton", first: true, predicate: ["ddBtn"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }], ngImport: i0, template: `
958
- <span #container [ngClass]="{ 'p-autocomplete p-component': true, 'p-autocomplete-dd': dropdown, 'p-autocomplete-multiple': multiple }" [ngStyle]="style" [class]="styleClass">
1156
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: AutoComplete, deps: [{ token: DOCUMENT }, { token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i1.PrimeNGConfig }, { token: i1.OverlayService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component });
1157
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: AutoComplete, selector: "p-autoComplete", inputs: { minLength: "minLength", delay: "delay", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", inputStyle: "inputStyle", inputId: "inputId", inputStyleClass: "inputStyleClass", placeholder: "placeholder", readonly: "readonly", disabled: "disabled", scrollHeight: "scrollHeight", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", maxlength: "maxlength", name: "name", required: "required", size: "size", appendTo: "appendTo", autoHighlight: "autoHighlight", forceSelection: "forceSelection", type: "type", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", ariaLabel: "ariaLabel", dropdownAriaLabel: "dropdownAriaLabel", ariaLabelledBy: "ariaLabelledBy", dropdownIcon: "dropdownIcon", unique: "unique", group: "group", completeOnFocus: "completeOnFocus", showClear: "showClear", field: "field", dropdown: "dropdown", showEmptyMessage: "showEmptyMessage", dropdownMode: "dropdownMode", multiple: "multiple", tabindex: "tabindex", dataKey: "dataKey", emptyMessage: "emptyMessage", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", autofocus: "autofocus", autocomplete: "autocomplete", optionGroupChildren: "optionGroupChildren", optionGroupLabel: "optionGroupLabel", overlayOptions: "overlayOptions", suggestions: "suggestions", itemSize: "itemSize", optionLabel: "optionLabel", id: "id", searchMessage: "searchMessage", emptySelectionMessage: "emptySelectionMessage", selectionMessage: "selectionMessage", autoOptionFocus: "autoOptionFocus", selectOnFocus: "selectOnFocus", searchLocale: "searchLocale", optionDisabled: "optionDisabled", focusOnHover: "focusOnHover" }, outputs: { completeMethod: "completeMethod", onSelect: "onSelect", onUnselect: "onUnselect", onFocus: "onFocus", onBlur: "onBlur", onDropdownClick: "onDropdownClick", onClear: "onClear", onKeyUp: "onKeyUp", onShow: "onShow", onHide: "onHide", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "((focused && !disabled) || autofocus) || overlayVisible", "class.p-autocomplete-clearable": "showClear && !disabled" }, classAttribute: "p-element p-inputwrapper" }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerEL", first: true, predicate: ["container"], descendants: true }, { propertyName: "inputEL", first: true, predicate: ["focusInput"], descendants: true }, { propertyName: "multiInputEl", first: true, predicate: ["multiIn"], descendants: true }, { propertyName: "multiContainerEL", first: true, predicate: ["multiContainer"], descendants: true }, { propertyName: "dropdownButton", first: true, predicate: ["ddBtn"], descendants: true }, { propertyName: "itemsViewChild", first: true, predicate: ["items"], descendants: true }, { propertyName: "scroller", first: true, predicate: ["scroller"], descendants: true }, { propertyName: "overlayViewChild", first: true, predicate: ["overlay"], descendants: true }], ngImport: i0, template: `
1158
+ <div #container [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
959
1159
  <input
1160
+ *ngIf="!multiple"
1161
+ #focusInput
960
1162
  pAutoFocus
961
1163
  [autofocus]="autofocus"
962
- *ngIf="!multiple"
963
- #in
964
- [attr.type]="type"
965
- [attr.id]="inputId"
1164
+ [ngClass]="inputClass"
966
1165
  [ngStyle]="inputStyle"
967
1166
  [class]="inputStyleClass"
1167
+ [type]="type"
1168
+ [attr.value]="inputValue()"
1169
+ [attr.id]="inputId"
968
1170
  [autocomplete]="autocomplete"
969
- [attr.required]="required"
970
- [attr.name]="name"
971
- class="p-autocomplete-input p-inputtext p-component"
972
- [ngClass]="{ 'p-autocomplete-dd-input': dropdown, 'p-disabled': disabled }"
973
- [value]="inputFieldValue"
1171
+ [required]="required"
1172
+ [name]="name"
974
1173
  aria-autocomplete="list"
975
- role="searchbox"
976
- (click)="onInputClick($event)"
977
- (input)="onInput($event)"
978
- (keydown)="onKeydown($event)"
979
- (keyup)="onKeyup($event)"
980
- (focus)="onInputFocus($event)"
981
- (blur)="onInputBlur($event)"
982
- (change)="onInputChange($event)"
983
- (paste)="onInputPaste($event)"
1174
+ role="combobox"
984
1175
  [attr.placeholder]="placeholder"
985
1176
  [attr.size]="size"
986
- [attr.maxlength]="maxlength"
987
- [attr.tabindex]="tabindex"
1177
+ [maxlength]="maxlength"
1178
+ [tabindex]="!disabled ? tabindex : -1"
988
1179
  [readonly]="readonly"
989
1180
  [disabled]="disabled"
990
1181
  [attr.aria-label]="ariaLabel"
991
1182
  [attr.aria-labelledby]="ariaLabelledBy"
992
1183
  [attr.aria-required]="required"
1184
+ [attr.aria-expanded]="overlayVisible"
1185
+ [attr.aria-controls]="id + '_list'"
1186
+ [attr.aria-aria-activedescendant]="focused ? focusedOptionId : undefined"
1187
+ (input)="onInput($event)"
1188
+ (keydown)="onKeyDown($event)"
1189
+ (change)="onInputChange($event)"
1190
+ (focus)="onInputFocus($event)"
1191
+ (blur)="onInputBlur($event)"
1192
+ (paste)="onInputPaste($event)"
1193
+ (keyup)="onInputKeyUp($event)"
993
1194
  />
994
1195
  <ng-container *ngIf="filled && !disabled && showClear && !loading">
995
- <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" />
996
- <span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()">
1196
+ <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" [attr.aria-hidden]="true" />
1197
+ <span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()" [attr.aria-hidden]="true">
997
1198
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
998
1199
  </span>
999
1200
  </ng-container>
1000
- <ul *ngIf="multiple" #multiContainer class="p-autocomplete-multiple-container p-component p-inputtext" [ngClass]="{ 'p-disabled': disabled, 'p-focus': focus }" (click)="multiIn.focus()">
1001
- <li #token *ngFor="let val of value" class="p-autocomplete-token">
1002
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: val }"></ng-container>
1003
- <span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ resolveFieldData(val) }}</span>
1004
- <span class="p-autocomplete-token-icon" (click)="removeItem(token)">
1005
- <TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" />
1006
- <span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon">
1201
+
1202
+ <ul
1203
+ *ngIf="multiple"
1204
+ #multiContainer
1205
+ [class]="multiContainerClass"
1206
+ [tabindex]="-1"
1207
+ role="listbox"
1208
+ [attr.aria-orientation]="'horizontal'"
1209
+ [attr.aria-activedescendant]="focused ? focusedMultipleOptionId : undefined"
1210
+ (focus)="onMultipleContainerFocus($event)"
1211
+ (blur)="onMultipleContainerBlur($event)"
1212
+ (keydown)="onMultipleContainerKeyDown($event)"
1213
+ >
1214
+ <li
1215
+ #token
1216
+ *ngFor="let option of modelValue(); let i = index"
1217
+ [ngClass]="{ 'p-autocomplete-token': true, 'p-focus': focusedMultipleOptionIndex() === i }"
1218
+ [attr.id]="id + '_multiple_option_' + i"
1219
+ role="option"
1220
+ [attr.aria-label]="getOptionLabel(option)"
1221
+ [attr.aria-setsize]="modelValue().length"
1222
+ [attr.aria-posinset]="i + 1"
1223
+ [attr.aria-selected]="true"
1224
+ >
1225
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: option }"></ng-container>
1226
+ <span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ getOptionLabel(option) }}</span>
1227
+ <span class="p-autocomplete-token-icon" (click)="removeOption($event, i)">
1228
+ <TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" [attr.aria-hidden]="true" />
1229
+ <span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon" [attr.aria-hidden]="true">
1007
1230
  <ng-template *ngTemplateOutlet="removeIconTemplate"></ng-template>
1008
1231
  </span>
1009
1232
  </span>
1010
1233
  </li>
1011
- <li class="p-autocomplete-input-token">
1234
+ <li class="p-autocomplete-input-token" role="option">
1012
1235
  <input
1236
+ #focusInput
1013
1237
  pAutoFocus
1014
1238
  [autofocus]="autofocus"
1015
- #multiIn
1239
+ [ngClass]="inputClass"
1240
+ [ngStyle]="inputStyle"
1241
+ [class]="inputStyleClass"
1016
1242
  [attr.type]="type"
1017
1243
  [attr.id]="inputId"
1018
- [disabled]="disabled"
1019
- [attr.placeholder]="value && value.length ? null : placeholder"
1020
- [attr.tabindex]="tabindex"
1021
- [attr.maxlength]="maxlength"
1022
- (input)="onInput($event)"
1023
- (click)="onInputClick($event)"
1024
- (keydown)="onKeydown($event)"
1025
- [readonly]="readonly"
1026
- (keyup)="onKeyup($event)"
1027
- (focus)="onInputFocus($event)"
1028
- (blur)="onInputBlur($event)"
1029
- (change)="onInputChange($event)"
1030
- (paste)="onInputPaste($event)"
1031
1244
  [autocomplete]="autocomplete"
1032
- [ngStyle]="inputStyle"
1033
- [class]="inputStyleClass"
1245
+ [required]="required"
1246
+ [attr.name]="name"
1247
+ role="combobox"
1248
+ [attr.placeholder]="placeholder"
1249
+ [attr.size]="size"
1250
+ aria-autocomplete="list"
1251
+ [maxlength]="maxlength"
1252
+ [tabindex]="!disabled ? tabindex : -1"
1253
+ [readonly]="readonly"
1254
+ [disabled]="disabled"
1034
1255
  [attr.aria-label]="ariaLabel"
1035
1256
  [attr.aria-labelledby]="ariaLabelledBy"
1036
1257
  [attr.aria-required]="required"
1037
- aria-autocomplete="list"
1038
- [attr.aria-controls]="listId"
1039
- role="searchbox"
1040
1258
  [attr.aria-expanded]="overlayVisible"
1041
- aria-haspopup="true"
1042
- [attr.aria-activedescendant]="'p-highlighted-option'"
1259
+ [attr.aria-controls]="id + '_list'"
1260
+ [attr.aria-aria-activedescendant]="focused ? focusedOptionId : undefined"
1261
+ (input)="onInput($event)"
1262
+ (keydown)="onKeyDown($event)"
1263
+ (change)="onInputChange($event)"
1264
+ (focus)="onInputFocus($event)"
1265
+ (blur)="onInputBlur($event)"
1266
+ (paste)="onInputPaste($event)"
1267
+ (keyup)="onInputKeyUp($event)"
1043
1268
  />
1044
1269
  </li>
1045
1270
  </ul>
1046
1271
  <ng-container *ngIf="loading">
1047
- <SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" />
1048
- <span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin ">
1272
+ <SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" [attr.aria-hidden]="true" />
1273
+ <span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin " [attr.aria-hidden]="true">
1049
1274
  <ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
1050
1275
  </span>
1051
1276
  </ng-container>
1052
1277
  <button #ddBtn type="button" pButton [attr.aria-label]="dropdownAriaLabel" class="p-autocomplete-dropdown p-button-icon-only" [disabled]="disabled" pRipple (click)="handleDropdownClick($event)" *ngIf="dropdown" [attr.tabindex]="tabindex">
1053
- <span *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1278
+ <span *ngIf="dropdownIcon" [ngClass]="dropdownIcon" [attr.aria-hidden]="true"></span>
1054
1279
  <ng-container *ngIf="!dropdownIcon">
1055
1280
  <ChevronDownIcon *ngIf="!dropdownIconTemplate" />
1056
1281
  <ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
@@ -1059,23 +1284,21 @@ class AutoComplete {
1059
1284
  <p-overlay
1060
1285
  #overlay
1061
1286
  [(visible)]="overlayVisible"
1062
- [options]="overlayOptions"
1287
+ [options]="virtualScrollOptions"
1063
1288
  [target]="'@parent'"
1064
1289
  [appendTo]="appendTo"
1065
- [autoZIndex]="autoZIndex"
1066
- [baseZIndex]="baseZIndex"
1067
1290
  [showTransitionOptions]="showTransitionOptions"
1068
1291
  [hideTransitionOptions]="hideTransitionOptions"
1069
1292
  (onAnimationStart)="onOverlayAnimationStart($event)"
1070
- (onShow)="show($event)"
1071
- (onHide)="hide($event)"
1293
+ (onHide)="hide()"
1072
1294
  >
1073
- <div [ngClass]="['p-autocomplete-panel p-component']" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
1295
+ <div [ngClass]="panelClass" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
1074
1296
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1075
1297
  <p-scroller
1076
1298
  *ngIf="virtualScroll"
1077
1299
  #scroller
1078
- [items]="suggestions"
1300
+ [items]="visibleOptions()"
1301
+ [tabindex]="-1"
1079
1302
  [style]="{ height: scrollHeight }"
1080
1303
  [itemSize]="virtualScrollItemSize || _itemSize"
1081
1304
  [autoSize]="true"
@@ -1093,151 +1316,181 @@ class AutoComplete {
1093
1316
  </ng-container>
1094
1317
  </p-scroller>
1095
1318
  <ng-container *ngIf="!virtualScroll">
1096
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: suggestions, options: {} }"></ng-container>
1319
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1097
1320
  </ng-container>
1098
1321
 
1099
1322
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1100
- <ul #items role="listbox" [attr.id]="listId" class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle">
1101
- <ng-container *ngIf="group">
1102
- <ng-template ngFor let-optgroup [ngForOf]="items">
1103
- <li class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1104
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1105
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1323
+ <ul #items class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" [attr.id]="id + '_list'">
1324
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1325
+ <ng-container *ngIf="isOptionGroup(option)">
1326
+ <li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1327
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1328
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1329
+ </li>
1330
+ </ng-container>
1331
+ <ng-container *ngIf="!isOptionGroup(option)">
1332
+ <li
1333
+ class="p-autocomplete-item"
1334
+ pRipple
1335
+ [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
1336
+ [ngClass]="{ 'p-highlight': isSelected(option), 'p-focus': focusedOptionIndex() === getOptionIndex(i, scrollerOptions), 'p-disabled': isOptionDisabled(option) }"
1337
+ [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1338
+ role="option"
1339
+ [attr.aria-label]="getOptionLabel(option)"
1340
+ [attr.aria-selected]="isSelected(option)"
1341
+ [attr.aria-disabled]="isOptionDisabled(option)"
1342
+ [attr.data-p-focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1343
+ [attr.aria-setsize]="ariaSetSize"
1344
+ [attr.aria-posinset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1345
+ (click)="onOptionSelect($event, option)"
1346
+ (mouseenter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1347
+ >
1348
+ <span *ngIf="!itemTemplate">{{ getOptionLabel(option) }}</span>
1349
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(i) : i }"></ng-container>
1106
1350
  </li>
1107
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup) }"></ng-container>
1108
- </ng-template>
1109
- </ng-container>
1110
- <ng-container *ngIf="!group">
1111
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items }"></ng-container>
1112
- </ng-container>
1113
- <ng-template #itemslist let-suggestionsToDisplay>
1114
- <li
1115
- role="option"
1116
- *ngFor="let option of suggestionsToDisplay; let idx = index"
1117
- class="p-autocomplete-item"
1118
- pRipple
1119
- [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
1120
- [ngClass]="{ 'p-highlight': option === highlightOption }"
1121
- [id]="highlightOption == option ? 'p-highlighted-option' : ''"
1122
- (click)="selectItem(option)"
1123
- >
1124
- <span *ngIf="!itemTemplate">{{ resolveFieldData(option) }}</span>
1125
- <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(idx) : idx }"></ng-container>
1126
- </li>
1351
+ </ng-container>
1127
1352
  </ng-template>
1128
- <li *ngIf="noResults && showEmptyMessage" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1353
+ <li *ngIf="!items || (items && items.length === 0 && showEmptyMessage)" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1129
1354
  <ng-container *ngIf="!emptyTemplate; else empty">
1130
- {{ emptyMessageLabel }}
1355
+ {{ searchResultMessageText }}
1131
1356
  </ng-container>
1132
1357
  <ng-container #empty *ngTemplateOutlet="emptyTemplate"></ng-container>
1133
1358
  </li>
1134
1359
  </ul>
1360
+ <ng-container *ngTemplateOutlet="footerTemplate; context: { $implicit: items }"></ng-container>
1361
+ <span role="status" aria-live="polite" class="p-hidden-accessible">
1362
+ {{ selectedMessageText }}
1363
+ </span>
1135
1364
  </ng-template>
1136
- <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
1137
1365
  </div>
1138
1366
  </p-overlay>
1139
- </span>
1367
+ </div>
1140
1368
  `, isInline: true, styles: ["@layer primeng{.p-autocomplete{display:inline-flex;position:relative}.p-autocomplete-loader{position:absolute;top:50%;margin-top:-.5rem}.p-autocomplete-dd .p-autocomplete-input{flex:1 1 auto;width:1%}.p-autocomplete-dd .p-autocomplete-input,.p-autocomplete-dd .p-autocomplete-multiple-container{border-top-right-radius:0;border-bottom-right-radius:0}.p-autocomplete-dd .p-autocomplete-dropdown{border-top-left-radius:0;border-bottom-left-radius:0}.p-autocomplete-panel{overflow:auto}.p-autocomplete-items{margin:0;padding:0;list-style-type:none}.p-autocomplete-item{cursor:pointer;white-space:nowrap;position:relative;overflow:hidden}.p-autocomplete-multiple-container{margin:0;padding:0;list-style-type:none;cursor:text;overflow:hidden;display:flex;align-items:center;flex-wrap:wrap}.p-autocomplete-token{width:-moz-fit-content;width:fit-content;cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-autocomplete-token-icon{display:flex;cursor:pointer}.p-autocomplete-input-token{flex:1 1 auto;display:inline-flex}.p-autocomplete-input-token input{border:0 none;outline:0 none;background-color:transparent;margin:0;padding:0;box-shadow:none;border-radius:0;width:100%}.p-fluid .p-autocomplete{display:flex}.p-fluid .p-autocomplete-dd .p-autocomplete-input{width:1%}.p-autocomplete-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-autocomplete-clearable{position:relative}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i2.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(function () { return i2.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i2.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(function () { return i2.NgTemplateOutlet; }), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(function () { return i2.NgStyle; }), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(function () { return i3.Overlay; }), selector: "p-overlay", inputs: ["visible", "mode", "style", "styleClass", "contentStyle", "contentStyleClass", "target", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "listener", "responsive", "options"], outputs: ["visibleChange", "onBeforeShow", "onShow", "onBeforeHide", "onHide", "onAnimationStart", "onAnimationDone"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.PrimeTemplate; }), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i4.ButtonDirective; }), selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading"] }, { kind: "directive", type: i0.forwardRef(function () { return i5.Ripple; }), selector: "[pRipple]" }, { kind: "component", type: i0.forwardRef(function () { return i6.Scroller; }), selector: "p-scroller", inputs: ["id", "style", "styleClass", "tabindex", "items", "itemSize", "scrollHeight", "scrollWidth", "orientation", "step", "delay", "resizeDelay", "appendOnly", "inline", "lazy", "disabled", "loaderDisabled", "columns", "showSpacer", "showLoader", "numToleratedItems", "loading", "autoSize", "trackBy", "options"], outputs: ["onLazyLoad", "onScroll", "onScrollIndexChange"] }, { kind: "directive", type: i0.forwardRef(function () { return i7.AutoFocus; }), selector: "[pAutoFocus]", inputs: ["autofocus"] }, { kind: "component", type: i0.forwardRef(function () { return TimesCircleIcon; }), selector: "TimesCircleIcon" }, { kind: "component", type: i0.forwardRef(function () { return SpinnerIcon; }), selector: "SpinnerIcon" }, { kind: "component", type: i0.forwardRef(function () { return TimesIcon; }), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(function () { return ChevronDownIcon; }), selector: "ChevronDownIcon" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1141
1369
  }
1142
1370
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: AutoComplete, decorators: [{
1143
1371
  type: Component,
1144
1372
  args: [{ selector: 'p-autoComplete', template: `
1145
- <span #container [ngClass]="{ 'p-autocomplete p-component': true, 'p-autocomplete-dd': dropdown, 'p-autocomplete-multiple': multiple }" [ngStyle]="style" [class]="styleClass">
1373
+ <div #container [ngClass]="containerClass" [ngStyle]="style" [class]="styleClass" (click)="onContainerClick($event)">
1146
1374
  <input
1375
+ *ngIf="!multiple"
1376
+ #focusInput
1147
1377
  pAutoFocus
1148
1378
  [autofocus]="autofocus"
1149
- *ngIf="!multiple"
1150
- #in
1151
- [attr.type]="type"
1152
- [attr.id]="inputId"
1379
+ [ngClass]="inputClass"
1153
1380
  [ngStyle]="inputStyle"
1154
1381
  [class]="inputStyleClass"
1382
+ [type]="type"
1383
+ [attr.value]="inputValue()"
1384
+ [attr.id]="inputId"
1155
1385
  [autocomplete]="autocomplete"
1156
- [attr.required]="required"
1157
- [attr.name]="name"
1158
- class="p-autocomplete-input p-inputtext p-component"
1159
- [ngClass]="{ 'p-autocomplete-dd-input': dropdown, 'p-disabled': disabled }"
1160
- [value]="inputFieldValue"
1386
+ [required]="required"
1387
+ [name]="name"
1161
1388
  aria-autocomplete="list"
1162
- role="searchbox"
1163
- (click)="onInputClick($event)"
1164
- (input)="onInput($event)"
1165
- (keydown)="onKeydown($event)"
1166
- (keyup)="onKeyup($event)"
1167
- (focus)="onInputFocus($event)"
1168
- (blur)="onInputBlur($event)"
1169
- (change)="onInputChange($event)"
1170
- (paste)="onInputPaste($event)"
1389
+ role="combobox"
1171
1390
  [attr.placeholder]="placeholder"
1172
1391
  [attr.size]="size"
1173
- [attr.maxlength]="maxlength"
1174
- [attr.tabindex]="tabindex"
1392
+ [maxlength]="maxlength"
1393
+ [tabindex]="!disabled ? tabindex : -1"
1175
1394
  [readonly]="readonly"
1176
1395
  [disabled]="disabled"
1177
1396
  [attr.aria-label]="ariaLabel"
1178
1397
  [attr.aria-labelledby]="ariaLabelledBy"
1179
1398
  [attr.aria-required]="required"
1399
+ [attr.aria-expanded]="overlayVisible"
1400
+ [attr.aria-controls]="id + '_list'"
1401
+ [attr.aria-aria-activedescendant]="focused ? focusedOptionId : undefined"
1402
+ (input)="onInput($event)"
1403
+ (keydown)="onKeyDown($event)"
1404
+ (change)="onInputChange($event)"
1405
+ (focus)="onInputFocus($event)"
1406
+ (blur)="onInputBlur($event)"
1407
+ (paste)="onInputPaste($event)"
1408
+ (keyup)="onInputKeyUp($event)"
1180
1409
  />
1181
1410
  <ng-container *ngIf="filled && !disabled && showClear && !loading">
1182
- <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" />
1183
- <span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()">
1411
+ <TimesIcon *ngIf="!clearIconTemplate" [styleClass]="'p-autocomplete-clear-icon'" (click)="clear()" [attr.aria-hidden]="true" />
1412
+ <span *ngIf="clearIconTemplate" class="p-autocomplete-clear-icon" (click)="clear()" [attr.aria-hidden]="true">
1184
1413
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1185
1414
  </span>
1186
1415
  </ng-container>
1187
- <ul *ngIf="multiple" #multiContainer class="p-autocomplete-multiple-container p-component p-inputtext" [ngClass]="{ 'p-disabled': disabled, 'p-focus': focus }" (click)="multiIn.focus()">
1188
- <li #token *ngFor="let val of value" class="p-autocomplete-token">
1189
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: val }"></ng-container>
1190
- <span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ resolveFieldData(val) }}</span>
1191
- <span class="p-autocomplete-token-icon" (click)="removeItem(token)">
1192
- <TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" />
1193
- <span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon">
1416
+
1417
+ <ul
1418
+ *ngIf="multiple"
1419
+ #multiContainer
1420
+ [class]="multiContainerClass"
1421
+ [tabindex]="-1"
1422
+ role="listbox"
1423
+ [attr.aria-orientation]="'horizontal'"
1424
+ [attr.aria-activedescendant]="focused ? focusedMultipleOptionId : undefined"
1425
+ (focus)="onMultipleContainerFocus($event)"
1426
+ (blur)="onMultipleContainerBlur($event)"
1427
+ (keydown)="onMultipleContainerKeyDown($event)"
1428
+ >
1429
+ <li
1430
+ #token
1431
+ *ngFor="let option of modelValue(); let i = index"
1432
+ [ngClass]="{ 'p-autocomplete-token': true, 'p-focus': focusedMultipleOptionIndex() === i }"
1433
+ [attr.id]="id + '_multiple_option_' + i"
1434
+ role="option"
1435
+ [attr.aria-label]="getOptionLabel(option)"
1436
+ [attr.aria-setsize]="modelValue().length"
1437
+ [attr.aria-posinset]="i + 1"
1438
+ [attr.aria-selected]="true"
1439
+ >
1440
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: option }"></ng-container>
1441
+ <span *ngIf="!selectedItemTemplate" class="p-autocomplete-token-label">{{ getOptionLabel(option) }}</span>
1442
+ <span class="p-autocomplete-token-icon" (click)="removeOption($event, i)">
1443
+ <TimesCircleIcon [styleClass]="'p-autocomplete-token-icon'" *ngIf="!removeIconTemplate" [attr.aria-hidden]="true" />
1444
+ <span *ngIf="removeIconTemplate" class="p-autocomplete-token-icon" [attr.aria-hidden]="true">
1194
1445
  <ng-template *ngTemplateOutlet="removeIconTemplate"></ng-template>
1195
1446
  </span>
1196
1447
  </span>
1197
1448
  </li>
1198
- <li class="p-autocomplete-input-token">
1449
+ <li class="p-autocomplete-input-token" role="option">
1199
1450
  <input
1451
+ #focusInput
1200
1452
  pAutoFocus
1201
1453
  [autofocus]="autofocus"
1202
- #multiIn
1454
+ [ngClass]="inputClass"
1455
+ [ngStyle]="inputStyle"
1456
+ [class]="inputStyleClass"
1203
1457
  [attr.type]="type"
1204
1458
  [attr.id]="inputId"
1205
- [disabled]="disabled"
1206
- [attr.placeholder]="value && value.length ? null : placeholder"
1207
- [attr.tabindex]="tabindex"
1208
- [attr.maxlength]="maxlength"
1209
- (input)="onInput($event)"
1210
- (click)="onInputClick($event)"
1211
- (keydown)="onKeydown($event)"
1212
- [readonly]="readonly"
1213
- (keyup)="onKeyup($event)"
1214
- (focus)="onInputFocus($event)"
1215
- (blur)="onInputBlur($event)"
1216
- (change)="onInputChange($event)"
1217
- (paste)="onInputPaste($event)"
1218
1459
  [autocomplete]="autocomplete"
1219
- [ngStyle]="inputStyle"
1220
- [class]="inputStyleClass"
1460
+ [required]="required"
1461
+ [attr.name]="name"
1462
+ role="combobox"
1463
+ [attr.placeholder]="placeholder"
1464
+ [attr.size]="size"
1465
+ aria-autocomplete="list"
1466
+ [maxlength]="maxlength"
1467
+ [tabindex]="!disabled ? tabindex : -1"
1468
+ [readonly]="readonly"
1469
+ [disabled]="disabled"
1221
1470
  [attr.aria-label]="ariaLabel"
1222
1471
  [attr.aria-labelledby]="ariaLabelledBy"
1223
1472
  [attr.aria-required]="required"
1224
- aria-autocomplete="list"
1225
- [attr.aria-controls]="listId"
1226
- role="searchbox"
1227
1473
  [attr.aria-expanded]="overlayVisible"
1228
- aria-haspopup="true"
1229
- [attr.aria-activedescendant]="'p-highlighted-option'"
1474
+ [attr.aria-controls]="id + '_list'"
1475
+ [attr.aria-aria-activedescendant]="focused ? focusedOptionId : undefined"
1476
+ (input)="onInput($event)"
1477
+ (keydown)="onKeyDown($event)"
1478
+ (change)="onInputChange($event)"
1479
+ (focus)="onInputFocus($event)"
1480
+ (blur)="onInputBlur($event)"
1481
+ (paste)="onInputPaste($event)"
1482
+ (keyup)="onInputKeyUp($event)"
1230
1483
  />
1231
1484
  </li>
1232
1485
  </ul>
1233
1486
  <ng-container *ngIf="loading">
1234
- <SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" />
1235
- <span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin ">
1487
+ <SpinnerIcon *ngIf="!loadingIconTemplate" [styleClass]="'p-autocomplete-loader'" [spin]="true" [attr.aria-hidden]="true" />
1488
+ <span *ngIf="loadingIconTemplate" class="p-autocomplete-loader pi-spin " [attr.aria-hidden]="true">
1236
1489
  <ng-template *ngTemplateOutlet="loadingIconTemplate"></ng-template>
1237
1490
  </span>
1238
1491
  </ng-container>
1239
1492
  <button #ddBtn type="button" pButton [attr.aria-label]="dropdownAriaLabel" class="p-autocomplete-dropdown p-button-icon-only" [disabled]="disabled" pRipple (click)="handleDropdownClick($event)" *ngIf="dropdown" [attr.tabindex]="tabindex">
1240
- <span *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1493
+ <span *ngIf="dropdownIcon" [ngClass]="dropdownIcon" [attr.aria-hidden]="true"></span>
1241
1494
  <ng-container *ngIf="!dropdownIcon">
1242
1495
  <ChevronDownIcon *ngIf="!dropdownIconTemplate" />
1243
1496
  <ng-template *ngTemplateOutlet="dropdownIconTemplate"></ng-template>
@@ -1246,23 +1499,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1246
1499
  <p-overlay
1247
1500
  #overlay
1248
1501
  [(visible)]="overlayVisible"
1249
- [options]="overlayOptions"
1502
+ [options]="virtualScrollOptions"
1250
1503
  [target]="'@parent'"
1251
1504
  [appendTo]="appendTo"
1252
- [autoZIndex]="autoZIndex"
1253
- [baseZIndex]="baseZIndex"
1254
1505
  [showTransitionOptions]="showTransitionOptions"
1255
1506
  [hideTransitionOptions]="hideTransitionOptions"
1256
1507
  (onAnimationStart)="onOverlayAnimationStart($event)"
1257
- (onShow)="show($event)"
1258
- (onHide)="hide($event)"
1508
+ (onHide)="hide()"
1259
1509
  >
1260
- <div [ngClass]="['p-autocomplete-panel p-component']" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
1510
+ <div [ngClass]="panelClass" [style.max-height]="virtualScroll ? 'auto' : scrollHeight" [ngStyle]="panelStyle" [class]="panelStyleClass">
1261
1511
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1262
1512
  <p-scroller
1263
1513
  *ngIf="virtualScroll"
1264
1514
  #scroller
1265
- [items]="suggestions"
1515
+ [items]="visibleOptions()"
1516
+ [tabindex]="-1"
1266
1517
  [style]="{ height: scrollHeight }"
1267
1518
  [itemSize]="virtualScrollItemSize || _itemSize"
1268
1519
  [autoSize]="true"
@@ -1280,60 +1531,65 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1280
1531
  </ng-container>
1281
1532
  </p-scroller>
1282
1533
  <ng-container *ngIf="!virtualScroll">
1283
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: suggestions, options: {} }"></ng-container>
1534
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1284
1535
  </ng-container>
1285
1536
 
1286
1537
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1287
- <ul #items role="listbox" [attr.id]="listId" class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle">
1288
- <ng-container *ngIf="group">
1289
- <ng-template ngFor let-optgroup [ngForOf]="items">
1290
- <li class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1291
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1292
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1538
+ <ul #items class="p-autocomplete-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox" [attr.id]="id + '_list'">
1539
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1540
+ <ng-container *ngIf="isOptionGroup(option)">
1541
+ <li [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" class="p-autocomplete-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1542
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1543
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1293
1544
  </li>
1294
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup) }"></ng-container>
1295
- </ng-template>
1296
- </ng-container>
1297
- <ng-container *ngIf="!group">
1298
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items }"></ng-container>
1299
- </ng-container>
1300
- <ng-template #itemslist let-suggestionsToDisplay>
1301
- <li
1302
- role="option"
1303
- *ngFor="let option of suggestionsToDisplay; let idx = index"
1304
- class="p-autocomplete-item"
1305
- pRipple
1306
- [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
1307
- [ngClass]="{ 'p-highlight': option === highlightOption }"
1308
- [id]="highlightOption == option ? 'p-highlighted-option' : ''"
1309
- (click)="selectItem(option)"
1310
- >
1311
- <span *ngIf="!itemTemplate">{{ resolveFieldData(option) }}</span>
1312
- <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(idx) : idx }"></ng-container>
1313
- </li>
1545
+ </ng-container>
1546
+ <ng-container *ngIf="!isOptionGroup(option)">
1547
+ <li
1548
+ class="p-autocomplete-item"
1549
+ pRipple
1550
+ [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }"
1551
+ [ngClass]="{ 'p-highlight': isSelected(option), 'p-focus': focusedOptionIndex() === getOptionIndex(i, scrollerOptions), 'p-disabled': isOptionDisabled(option) }"
1552
+ [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1553
+ role="option"
1554
+ [attr.aria-label]="getOptionLabel(option)"
1555
+ [attr.aria-selected]="isSelected(option)"
1556
+ [attr.aria-disabled]="isOptionDisabled(option)"
1557
+ [attr.data-p-focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1558
+ [attr.aria-setsize]="ariaSetSize"
1559
+ [attr.aria-posinset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1560
+ (click)="onOptionSelect($event, option)"
1561
+ (mouseenter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1562
+ >
1563
+ <span *ngIf="!itemTemplate">{{ getOptionLabel(option) }}</span>
1564
+ <ng-container *ngTemplateOutlet="itemTemplate; context: { $implicit: option, index: scrollerOptions.getOptions ? scrollerOptions.getOptions(i) : i }"></ng-container>
1565
+ </li>
1566
+ </ng-container>
1314
1567
  </ng-template>
1315
- <li *ngIf="noResults && showEmptyMessage" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1568
+ <li *ngIf="!items || (items && items.length === 0 && showEmptyMessage)" class="p-autocomplete-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1316
1569
  <ng-container *ngIf="!emptyTemplate; else empty">
1317
- {{ emptyMessageLabel }}
1570
+ {{ searchResultMessageText }}
1318
1571
  </ng-container>
1319
1572
  <ng-container #empty *ngTemplateOutlet="emptyTemplate"></ng-container>
1320
1573
  </li>
1321
1574
  </ul>
1575
+ <ng-container *ngTemplateOutlet="footerTemplate; context: { $implicit: items }"></ng-container>
1576
+ <span role="status" aria-live="polite" class="p-hidden-accessible">
1577
+ {{ selectedMessageText }}
1578
+ </span>
1322
1579
  </ng-template>
1323
- <ng-container *ngTemplateOutlet="footerTemplate"></ng-container>
1324
1580
  </div>
1325
1581
  </p-overlay>
1326
- </span>
1582
+ </div>
1327
1583
  `, host: {
1328
1584
  class: 'p-element p-inputwrapper',
1329
1585
  '[class.p-inputwrapper-filled]': 'filled',
1330
- '[class.p-inputwrapper-focus]': '((focus && !disabled) || autofocus) || overlayVisible',
1586
+ '[class.p-inputwrapper-focus]': '((focused && !disabled) || autofocus) || overlayVisible',
1331
1587
  '[class.p-autocomplete-clearable]': 'showClear && !disabled'
1332
1588
  }, providers: [AUTOCOMPLETE_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-autocomplete{display:inline-flex;position:relative}.p-autocomplete-loader{position:absolute;top:50%;margin-top:-.5rem}.p-autocomplete-dd .p-autocomplete-input{flex:1 1 auto;width:1%}.p-autocomplete-dd .p-autocomplete-input,.p-autocomplete-dd .p-autocomplete-multiple-container{border-top-right-radius:0;border-bottom-right-radius:0}.p-autocomplete-dd .p-autocomplete-dropdown{border-top-left-radius:0;border-bottom-left-radius:0}.p-autocomplete-panel{overflow:auto}.p-autocomplete-items{margin:0;padding:0;list-style-type:none}.p-autocomplete-item{cursor:pointer;white-space:nowrap;position:relative;overflow:hidden}.p-autocomplete-multiple-container{margin:0;padding:0;list-style-type:none;cursor:text;overflow:hidden;display:flex;align-items:center;flex-wrap:wrap}.p-autocomplete-token{width:-moz-fit-content;width:fit-content;cursor:default;display:inline-flex;align-items:center;flex:0 0 auto}.p-autocomplete-token-icon{display:flex;cursor:pointer}.p-autocomplete-input-token{flex:1 1 auto;display:inline-flex}.p-autocomplete-input-token input{border:0 none;outline:0 none;background-color:transparent;margin:0;padding:0;box-shadow:none;border-radius:0;width:100%}.p-fluid .p-autocomplete{display:flex}.p-fluid .p-autocomplete-dd .p-autocomplete-input{width:1%}.p-autocomplete-clear-icon{position:absolute;top:50%;margin-top:-.5rem;cursor:pointer}.p-autocomplete-clearable{position:relative}}\n"] }]
1333
1589
  }], ctorParameters: function () { return [{ type: Document, decorators: [{
1334
1590
  type: Inject,
1335
1591
  args: [DOCUMENT]
1336
- }] }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.IterableDiffers }, { type: i1.PrimeNGConfig }, { type: i1.OverlayService }, { type: i0.NgZone }]; }, propDecorators: { minLength: [{
1592
+ }] }, { type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i1.PrimeNGConfig }, { type: i1.OverlayService }, { type: i0.NgZone }]; }, propDecorators: { minLength: [{
1337
1593
  type: Input
1338
1594
  }], delay: [{
1339
1595
  type: Input
@@ -1437,6 +1693,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1437
1693
  type: Input
1438
1694
  }], itemSize: [{
1439
1695
  type: Input
1696
+ }], optionLabel: [{
1697
+ type: Input
1698
+ }], id: [{
1699
+ type: Input
1700
+ }], searchMessage: [{
1701
+ type: Input
1702
+ }], emptySelectionMessage: [{
1703
+ type: Input
1704
+ }], selectionMessage: [{
1705
+ type: Input
1706
+ }], autoOptionFocus: [{
1707
+ type: Input
1708
+ }], selectOnFocus: [{
1709
+ type: Input
1710
+ }], searchLocale: [{
1711
+ type: Input
1712
+ }], optionDisabled: [{
1713
+ type: Input
1714
+ }], focusOnHover: [{
1715
+ type: Input
1440
1716
  }], completeMethod: [{
1441
1717
  type: Output
1442
1718
  }], onSelect: [{
@@ -1464,7 +1740,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1464
1740
  args: ['container']
1465
1741
  }], inputEL: [{
1466
1742
  type: ViewChild,
1467
- args: ['in']
1743
+ args: ['focusInput']
1468
1744
  }], multiInputEl: [{
1469
1745
  type: ViewChild,
1470
1746
  args: ['multiIn']