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,7 +1,7 @@
1
1
  import * as i1 from '@angular/common';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import * as i0 from '@angular/core';
4
- import { forwardRef, EventEmitter, Component, Input, Output, ChangeDetectionStrategy, ViewEncapsulation, ViewChild, ContentChildren, NgModule } from '@angular/core';
4
+ import { forwardRef, EventEmitter, Component, Input, Output, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, ViewChild, ContentChildren, NgModule } from '@angular/core';
5
5
  import { NG_VALUE_ACCESSOR } from '@angular/forms';
6
6
  import * as i3 from 'primeng/api';
7
7
  import { TranslationKeys, PrimeTemplate, SharedModule } from 'primeng/api';
@@ -27,31 +27,43 @@ const DROPDOWN_VALUE_ACCESSOR = {
27
27
  multi: true
28
28
  };
29
29
  class DropdownItem {
30
+ id;
30
31
  option;
31
32
  selected;
33
+ focused;
32
34
  label;
33
35
  disabled;
34
36
  visible;
35
37
  itemSize;
38
+ ariaPosInset;
39
+ ariaSetSize;
36
40
  template;
37
41
  onClick = new EventEmitter();
42
+ onMouseEnter = new EventEmitter();
43
+ ngOnInit() { }
38
44
  onOptionClick(event) {
39
- this.onClick.emit({
40
- originalEvent: event,
41
- option: this.option
42
- });
45
+ this.onClick.emit(event);
46
+ }
47
+ onOptionMouseEnter(event) {
48
+ this.onMouseEnter.emit(event);
43
49
  }
44
50
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: DropdownItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
45
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: DropdownItem, selector: "p-dropdownItem", inputs: { option: "option", selected: "selected", label: "label", disabled: "disabled", visible: "visible", itemSize: "itemSize", template: "template" }, outputs: { onClick: "onClick" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
51
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: DropdownItem, selector: "p-dropdownItem", inputs: { id: "id", option: "option", selected: "selected", focused: "focused", label: "label", disabled: "disabled", visible: "visible", itemSize: "itemSize", ariaPosInset: "ariaPosInset", ariaSetSize: "ariaSetSize", template: "template" }, outputs: { onClick: "onClick", onMouseEnter: "onMouseEnter" }, host: { classAttribute: "p-element" }, ngImport: i0, template: `
46
52
  <li
53
+ [id]="id"
47
54
  (click)="onOptionClick($event)"
55
+ (mouseenter)="onOptionMouseEnter($event)"
48
56
  role="option"
49
57
  pRipple
50
58
  [attr.aria-label]="label"
59
+ [attr.aria-setsize]="ariaSetSize"
60
+ [attr.aria-posinset]="ariaPosInset"
51
61
  [attr.aria-selected]="selected"
62
+ [attr.data-p-focused]="focused"
63
+ [attr.data-p-highlight]="selected"
64
+ [attr.data-p-disabled]="disabled"
52
65
  [ngStyle]="{ height: itemSize + 'px' }"
53
- [id]="selected ? 'p-highlighted-option' : ''"
54
- [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled }"
66
+ [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
55
67
  >
56
68
  <span *ngIf="!template">{{ label ?? 'empty' }}</span>
57
69
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
@@ -64,14 +76,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
64
76
  selector: 'p-dropdownItem',
65
77
  template: `
66
78
  <li
79
+ [id]="id"
67
80
  (click)="onOptionClick($event)"
81
+ (mouseenter)="onOptionMouseEnter($event)"
68
82
  role="option"
69
83
  pRipple
70
84
  [attr.aria-label]="label"
85
+ [attr.aria-setsize]="ariaSetSize"
86
+ [attr.aria-posinset]="ariaPosInset"
71
87
  [attr.aria-selected]="selected"
88
+ [attr.data-p-focused]="focused"
89
+ [attr.data-p-highlight]="selected"
90
+ [attr.data-p-disabled]="disabled"
72
91
  [ngStyle]="{ height: itemSize + 'px' }"
73
- [id]="selected ? 'p-highlighted-option' : ''"
74
- [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled }"
92
+ [ngClass]="{ 'p-dropdown-item': true, 'p-highlight': selected, 'p-disabled': disabled, 'p-focus': focused }"
75
93
  >
76
94
  <span *ngIf="!template">{{ label ?? 'empty' }}</span>
77
95
  <ng-container *ngTemplateOutlet="template; context: { $implicit: option }"></ng-container>
@@ -81,10 +99,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
81
99
  class: 'p-element'
82
100
  }
83
101
  }]
84
- }], propDecorators: { option: [{
102
+ }], propDecorators: { id: [{
103
+ type: Input
104
+ }], option: [{
85
105
  type: Input
86
106
  }], selected: [{
87
107
  type: Input
108
+ }], focused: [{
109
+ type: Input
88
110
  }], label: [{
89
111
  type: Input
90
112
  }], disabled: [{
@@ -93,10 +115,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
93
115
  type: Input
94
116
  }], itemSize: [{
95
117
  type: Input
118
+ }], ariaPosInset: [{
119
+ type: Input
120
+ }], ariaSetSize: [{
121
+ type: Input
96
122
  }], template: [{
97
123
  type: Input
98
124
  }], onClick: [{
99
125
  type: Output
126
+ }], onMouseEnter: [{
127
+ type: Output
100
128
  }] } });
101
129
  /**
102
130
  * Dropdown also known as Select, is used to choose an item from a collection of options.
@@ -109,6 +137,11 @@ class Dropdown {
109
137
  zone;
110
138
  filterService;
111
139
  config;
140
+ /**
141
+ * Unique identifier of the component
142
+ * @group Props
143
+ */
144
+ id;
112
145
  /**
113
146
  * Height of the viewport in pixels, a scrollbar is defined if height of list exceeds this value.
114
147
  * @group Props
@@ -168,7 +201,7 @@ class Dropdown {
168
201
  * Index of the element in tabbing order.
169
202
  * @group Props
170
203
  */
171
- tabindex;
204
+ tabindex = 0;
172
205
  /**
173
206
  * Default text to display when no option is selected.
174
207
  * @group Props
@@ -199,6 +232,11 @@ class Dropdown {
199
232
  * @group Props
200
233
  */
201
234
  filterBy;
235
+ /**
236
+ * Fields used when filtering the options, defaults to optionLabel.
237
+ * @group Props
238
+ */
239
+ filterFields;
202
240
  /**
203
241
  * When present, it specifies that the component should automatically get focus on load.
204
242
  * @group Props
@@ -233,7 +271,7 @@ class Dropdown {
233
271
  * Name of the label field of an option group.
234
272
  * @group Props
235
273
  */
236
- optionGroupLabel;
274
+ optionGroupLabel = 'label';
237
275
  /**
238
276
  * Name of the options field of an option group.
239
277
  * @group Props
@@ -334,6 +372,21 @@ class Dropdown {
334
372
  * @group Props
335
373
  */
336
374
  tooltipStyleClass;
375
+ /**
376
+ * Fields used when filtering the options, defaults to optionLabel.
377
+ * @group Props
378
+ */
379
+ focusOnHover = false;
380
+ /**
381
+ * Determines if the option will be selected on focus.
382
+ * @group Props
383
+ */
384
+ selectOnFocus = false;
385
+ /**
386
+ * Whether to focus on the first visible or selected element when the overlay panel is shown.
387
+ * @group Props
388
+ */
389
+ autoOptionFocus = true;
337
390
  /**
338
391
  * Applies focus to the filter element when the overlay is shown.
339
392
  * @group Props
@@ -427,32 +480,21 @@ class Dropdown {
427
480
  * @group Props
428
481
  */
429
482
  get filterValue() {
430
- return this._filterValue;
483
+ return this._filterValue();
431
484
  }
432
485
  set filterValue(val) {
433
- this._filterValue = val;
434
- this.activateFilter();
486
+ this._filterValue.set(val);
435
487
  }
436
488
  /**
437
489
  * An array of objects to display as the available options.
438
490
  * @group Props
439
491
  */
440
492
  get options() {
441
- return this._options;
493
+ const options = this._options();
494
+ return options;
442
495
  }
443
496
  set options(val) {
444
- this._options = val;
445
- this.optionsToDisplay = this._options;
446
- this.updateSelectedOption(this.value);
447
- this.selectedOption = this.findOption(this.value, this.optionsToDisplay);
448
- if (!this.selectedOption && ObjectUtils.isNotEmpty(this.value) && !this.editable) {
449
- this.value = null;
450
- this.onModelChange(this.value);
451
- }
452
- this.optionsChanged = true;
453
- if (this._filterValue && this._filterValue.length) {
454
- this.activateFilter();
455
- }
497
+ this._options.set(val);
456
498
  }
457
499
  /**
458
500
  * Callback to invoke when value of dropdown changes.
@@ -510,11 +552,12 @@ class Dropdown {
510
552
  onLazyLoad = new EventEmitter();
511
553
  containerViewChild;
512
554
  filterViewChild;
513
- accessibleViewChild;
555
+ focusInputViewChild;
514
556
  editableInputViewChild;
515
557
  itemsViewChild;
516
558
  scroller;
517
559
  overlayViewChild;
560
+ firstHiddenFocusableElementOnOverlay;
518
561
  templates;
519
562
  _disabled;
520
563
  itemsWrapper;
@@ -531,12 +574,11 @@ class Dropdown {
531
574
  clearIconTemplate;
532
575
  filterIconTemplate;
533
576
  filterOptions;
534
- selectedOption;
535
- _options;
577
+ _options = signal(null);
578
+ modelValue = signal(null);
536
579
  value;
537
580
  onModelChange = () => { };
538
581
  onModelTouched = () => { };
539
- optionsToDisplay;
540
582
  hover;
541
583
  focused;
542
584
  overlayVisible;
@@ -545,16 +587,81 @@ class Dropdown {
545
587
  dimensionsUpdated;
546
588
  hoveredItem;
547
589
  selectedOptionUpdated;
548
- _filterValue;
590
+ _filterValue = signal(null);
549
591
  searchValue;
550
592
  searchIndex;
551
593
  searchTimeout;
552
594
  previousSearchChar;
553
595
  currentSearchChar;
554
596
  preventModelTouched;
555
- id = UniqueComponentId();
597
+ focusedOptionIndex = signal(-1);
556
598
  labelId;
557
599
  listId;
600
+ get emptyMessageLabel() {
601
+ return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
602
+ }
603
+ get emptyFilterMessageLabel() {
604
+ return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
605
+ }
606
+ get filled() {
607
+ if (typeof this.modelValue() === 'string')
608
+ return !!this.modelValue();
609
+ return this.modelValue() || this.modelValue() != null || this.modelValue() != undefined;
610
+ }
611
+ get isVisibleClearIcon() {
612
+ return this.modelValue() != null && ObjectUtils.isNotEmpty(this.modelValue()) && this.modelValue() !== '' && this.showClear && !this.disabled;
613
+ }
614
+ get containerClass() {
615
+ return {
616
+ 'p-dropdown p-component p-inputwrapper': true,
617
+ 'p-disabled': this.disabled,
618
+ 'p-dropdown-clearable': this.showClear && !this.disabled,
619
+ 'p-focus': this.focused,
620
+ 'p-inputwrapper-filled': this.modelValue(),
621
+ 'p-inputwrapper-focus': this.focused || this.overlayVisible
622
+ };
623
+ }
624
+ get inputClass() {
625
+ const label = this.label();
626
+ return {
627
+ 'p-dropdown-label p-inputtext': true,
628
+ 'p-placeholder': this.placeholder && label === this.placeholder,
629
+ 'p-dropdown-label-empty': !this.editable && !this.selectedItemTemplate && (!label || label === 'p-emptylabel' || label.length === 0)
630
+ };
631
+ }
632
+ get panelClass() {
633
+ return {
634
+ 'p-dropdown-panel p-component': true,
635
+ 'p-input-filled': this.config.inputStyle === 'filled',
636
+ 'p-ripple-disabled': this.config.ripple === false
637
+ };
638
+ }
639
+ visibleOptions = computed(() => {
640
+ const options = this.group ? this.flatOptions(this.options) : this.options || [];
641
+ if (this._filterValue()) {
642
+ const filteredOptions = !this.filterBy && !this.filterFields && !this.optionValue
643
+ ? this.options.filter((option) => option.toLowerCase().indexOf(this._filterValue().toLowerCase()) !== -1)
644
+ : this.filterService.filter(options, this.searchFields(), this._filterValue(), this.filterMatchMode, this.filterLocale);
645
+ if (this.group) {
646
+ const optionGroups = this.options || [];
647
+ const filtered = [];
648
+ optionGroups.forEach((group) => {
649
+ const groupChildren = this.getOptionGroupChildren(group);
650
+ const filteredItems = groupChildren.filter((item) => filteredOptions.includes(item));
651
+ if (filteredItems.length > 0)
652
+ filtered.push({ ...group, [typeof this.optionGroupChildren === 'string' ? this.optionGroupChildren : 'items']: [...filteredItems] });
653
+ });
654
+ return this.flatOptions(filtered);
655
+ }
656
+ return filteredOptions;
657
+ }
658
+ return options;
659
+ });
660
+ label = computed(() => {
661
+ let selectedOptionIndex;
662
+ this.autoDisplayFirst ? (!this.modelValue() ? (selectedOptionIndex = -1) : (selectedOptionIndex = this.findFirstOptionIndex())) : (selectedOptionIndex = this.findSelectedOptionIndex());
663
+ return this.modelValue() ? this.getOptionLabel(this.modelValue()) : selectedOptionIndex !== -1 ? this.getOptionLabel(this.visibleOptions()[selectedOptionIndex]) : this.placeholder || 'p-emptylabel';
664
+ });
558
665
  constructor(el, renderer, cd, zone, filterService, config) {
559
666
  this.el = el;
560
667
  this.renderer = renderer;
@@ -562,6 +669,41 @@ class Dropdown {
562
669
  this.zone = zone;
563
670
  this.filterService = filterService;
564
671
  this.config = config;
672
+ effect(() => {
673
+ const modelValue = this.modelValue();
674
+ if (modelValue && this.editable) {
675
+ this.updateEditableLabel();
676
+ }
677
+ });
678
+ }
679
+ ngOnInit() {
680
+ this.id = this.id || UniqueComponentId();
681
+ this.autoUpdateModel();
682
+ if (this.filterBy) {
683
+ this.filterOptions = {
684
+ filter: (value) => this.onFilterInputChange(value),
685
+ reset: () => this.resetFilter()
686
+ };
687
+ }
688
+ }
689
+ ngAfterViewChecked() {
690
+ if (this.optionsChanged && this.overlayVisible) {
691
+ this.optionsChanged = false;
692
+ this.zone.runOutsideAngular(() => {
693
+ setTimeout(() => {
694
+ if (this.overlayViewChild) {
695
+ this.overlayViewChild.alignOverlay();
696
+ }
697
+ }, 1);
698
+ });
699
+ }
700
+ if (this.selectedOptionUpdated && this.itemsWrapper) {
701
+ let selectedItem = DomHandler.findSingle(this.overlayViewChild?.overlayViewChild?.nativeElement, 'li.p-highlight');
702
+ if (selectedItem) {
703
+ DomHandler.scrollInView(this.itemsWrapper, selectedItem);
704
+ }
705
+ this.selectedOptionUpdated = false;
706
+ }
565
707
  }
566
708
  ngAfterContentInit() {
567
709
  this.templates.forEach((item) => {
@@ -608,48 +750,63 @@ class Dropdown {
608
750
  }
609
751
  });
610
752
  }
611
- ngOnInit() {
612
- this.optionsToDisplay = this.options;
613
- this.updateSelectedOption(null);
614
- this.labelId = this.id + '_label';
615
- this.listId = this.id + '_list';
616
- if (this.filterBy) {
617
- this.filterOptions = {
618
- filter: (value) => this.onFilterInputChange(value),
619
- reset: () => this.resetFilter()
620
- };
753
+ flatOptions(options) {
754
+ return (options || []).reduce((result, option, index) => {
755
+ result.push({ optionGroup: option, group: true, index });
756
+ const optionGroupChildren = this.getOptionGroupChildren(option);
757
+ optionGroupChildren && optionGroupChildren.forEach((o) => result.push(o));
758
+ return result;
759
+ }, []);
760
+ }
761
+ autoUpdateModel() {
762
+ if (this.selectOnFocus && this.autoOptionFocus && !this.hasSelectedOption()) {
763
+ this.focusedOptionIndex.set(this.findFirstFocusedOptionIndex());
764
+ this.onOptionSelect(null, this.visibleOptions()[this.focusedOptionIndex()], false);
621
765
  }
622
- }
623
- ngAfterViewInit() {
624
- if (this.editable) {
625
- this.updateEditableLabel();
766
+ if (this.autoDisplayFirst && !this.modelValue()) {
767
+ const ind = this.findFirstOptionIndex();
768
+ this.onOptionSelect(null, this.visibleOptions()[ind], false);
626
769
  }
627
770
  }
628
- get label() {
629
- if (typeof this.selectedOption === 'number') {
630
- this.selectedOption = this.selectedOption.toString();
631
- }
632
- return this.selectedOption ? this.getOptionLabel(this.selectedOption) : null;
771
+ onOptionSelect(event, option, isHide = true) {
772
+ const value = this.getOptionValue(option);
773
+ this.updateModel(value, event);
774
+ this.focusedOptionIndex.set(this.findSelectedOptionIndex());
775
+ isHide && this.hide(true);
633
776
  }
634
- get emptyMessageLabel() {
635
- return this.emptyMessage || this.config.getTranslation(TranslationKeys.EMPTY_MESSAGE);
777
+ onOptionMouseEnter(event, index) {
778
+ if (this.focusOnHover) {
779
+ this.changeFocusedOptionIndex(event, index);
780
+ }
636
781
  }
637
- get emptyFilterMessageLabel() {
638
- return this.emptyFilterMessage || this.config.getTranslation(TranslationKeys.EMPTY_FILTER_MESSAGE);
782
+ updateModel(value, event) {
783
+ this.value = value;
784
+ this.onModelChange(value);
785
+ if (this.value !== this.modelValue()) {
786
+ this.onChange.emit({
787
+ originalEvent: event,
788
+ value: value
789
+ });
790
+ }
791
+ this.modelValue.set(value);
792
+ this.selectedOptionUpdated = true;
639
793
  }
640
- get filled() {
641
- if (typeof this.value === 'string')
642
- return !!this.value;
643
- return this.value || this.value != null || this.value != undefined;
794
+ isSelected(option) {
795
+ return this.isValidOption(option) && ObjectUtils.equals(this.modelValue(), this.getOptionValue(option), this.equalityKey());
644
796
  }
645
- get isVisibleClearIcon() {
646
- return this.value != null && this.value !== '' && this.showClear && !this.disabled;
797
+ ngAfterViewInit() {
798
+ if (this.editable) {
799
+ this.updateEditableLabel();
800
+ }
647
801
  }
648
802
  updateEditableLabel() {
649
- if (this.editableInputViewChild && this.editableInputViewChild.nativeElement) {
650
- this.editableInputViewChild.nativeElement.value = this.selectedOption ? this.getOptionLabel(this.selectedOption) : this.value || '';
803
+ if (this.editableInputViewChild) {
804
+ this.editableInputViewChild.nativeElement.value = this.getOptionLabel(this.modelValue()) === undefined ? this.editableInputViewChild.nativeElement.value : this.getOptionLabel(this.modelValue());
651
805
  }
652
806
  }
807
+ getOptionIndex(index, scrollerOptions) {
808
+ return this.virtualScrollerDisabled ? index : scrollerOptions && scrollerOptions.getItemOptions(index)['index'];
809
+ }
653
810
  getOptionLabel(option) {
654
811
  return this.optionLabel ? ObjectUtils.resolveFieldData(option, this.optionLabel) : option && option.label !== undefined ? option.label : option;
655
812
  }
@@ -665,53 +822,23 @@ class Dropdown {
665
822
  getOptionGroupChildren(optionGroup) {
666
823
  return this.optionGroupChildren ? ObjectUtils.resolveFieldData(optionGroup, this.optionGroupChildren) : optionGroup.items;
667
824
  }
668
- onItemClick(event) {
669
- const option = event.option;
670
- if (!this.isOptionDisabled(option)) {
671
- this.selectItem(event.originalEvent, option);
672
- this.accessibleViewChild?.nativeElement.focus({ preventScroll: true });
673
- }
674
- setTimeout(() => {
675
- this.hide();
676
- }, 1);
825
+ getAriaPosInset(index) {
826
+ return ((this.optionGroupLabel
827
+ ? index -
828
+ this.visibleOptions()
829
+ .slice(0, index)
830
+ .filter((option) => this.isOptionGroup(option)).length
831
+ : index) + 1);
677
832
  }
678
- selectItem(event, option) {
679
- if (this.selectedOption != option) {
680
- this.selectedOption = option;
681
- this.value = this.getOptionValue(option);
682
- this.onModelChange(this.value);
683
- this.updateEditableLabel();
684
- this.onChange.emit({
685
- originalEvent: event,
686
- value: this.value
687
- });
688
- }
689
- }
690
- ngAfterViewChecked() {
691
- if (this.optionsChanged && this.overlayVisible) {
692
- this.optionsChanged = false;
693
- this.zone.runOutsideAngular(() => {
694
- setTimeout(() => {
695
- if (this.overlayViewChild) {
696
- this.overlayViewChild.alignOverlay();
697
- }
698
- }, 1);
699
- });
700
- }
701
- if (this.selectedOptionUpdated && this.itemsWrapper) {
702
- let selectedItem = DomHandler.findSingle(this.overlayViewChild?.overlayViewChild?.nativeElement, 'li.p-highlight');
703
- if (selectedItem) {
704
- DomHandler.scrollInView(this.itemsWrapper, selectedItem);
705
- }
706
- this.selectedOptionUpdated = false;
707
- }
833
+ get ariaSetSize() {
834
+ return this.visibleOptions().filter((option) => !this.isOptionGroup(option)).length;
708
835
  }
709
836
  writeValue(value) {
710
837
  if (this.filter) {
711
838
  this.resetFilter();
712
839
  }
713
840
  this.value = value;
714
- this.updateSelectedOption(value);
841
+ this.updateModel(this.value);
715
842
  this.updateEditableLabel();
716
843
  this.cd.markForCheck();
717
844
  }
@@ -720,25 +847,10 @@ class Dropdown {
720
847
  * @group Method
721
848
  */
722
849
  resetFilter() {
723
- this._filterValue = null;
850
+ this._filterValue.set(null);
724
851
  if (this.filterViewChild && this.filterViewChild.nativeElement) {
725
852
  this.filterViewChild.nativeElement.value = '';
726
853
  }
727
- this.optionsToDisplay = this.options;
728
- }
729
- updateSelectedOption(val) {
730
- this.selectedOption = this.findOption(val, this.optionsToDisplay);
731
- if (this.autoDisplayFirst && !this.placeholder && !this.selectedOption && this.optionsToDisplay && this.optionsToDisplay.length && !this.editable) {
732
- if (this.group) {
733
- this.selectedOption = this.getOptionGroupChildren(this.optionsToDisplay[0])[0];
734
- }
735
- else {
736
- this.selectedOption = this.optionsToDisplay[0];
737
- }
738
- this.value = this.getOptionValue(this.selectedOption);
739
- this.onModelChange(this.value);
740
- }
741
- this.selectedOptionUpdated = true;
742
854
  }
743
855
  registerOnChange(fn) {
744
856
  this.onModelChange = fn;
@@ -750,48 +862,42 @@ class Dropdown {
750
862
  this.disabled = val;
751
863
  this.cd.markForCheck();
752
864
  }
753
- onMouseclick(event) {
754
- if (this.disabled || this.readonly || this.isInputClick(event)) {
865
+ onContainerClick(event) {
866
+ if (this.disabled || this.readonly) {
755
867
  return;
756
868
  }
869
+ this.focusInputViewChild?.nativeElement.focus({ preventScroll: true });
870
+ if (event.target.tagName === 'INPUT' || event.target.getAttribute('data-pc-section') === 'clearicon' || event.target.closest('[data-pc-section="clearicon"]')) {
871
+ return;
872
+ }
873
+ else if (!this.overlayViewChild || !this.overlayViewChild.el.nativeElement.contains(event.target)) {
874
+ this.overlayVisible ? this.hide(true) : this.show(true);
875
+ }
757
876
  this.onClick.emit(event);
758
- this.accessibleViewChild?.nativeElement.focus({ preventScroll: true });
759
- if (this.overlayVisible)
760
- this.hide();
761
- else
762
- this.show();
763
877
  this.cd.detectChanges();
764
878
  }
765
- isInputClick(event) {
766
- const target = event.target;
767
- return (DomHandler.hasClass(target, 'p-dropdown-clear-icon') ||
768
- target.closest('.p-dropdown-clear-icon') !== null ||
769
- target.isSameNode(this.accessibleViewChild?.nativeElement) ||
770
- (this.editableInputViewChild && target.isSameNode(this.editableInputViewChild.nativeElement)));
771
- }
772
879
  isEmpty() {
773
- return !this.optionsToDisplay || (this.optionsToDisplay && this.optionsToDisplay.length === 0);
880
+ return !this._options() || (this._options() && this._options().length === 0);
774
881
  }
775
- onEditableInputFocus(event) {
776
- this.focused = true;
777
- this.hide();
778
- this.onFocus.emit(event);
779
- }
780
- onEditableInputChange(event) {
781
- this.value = event.target.value;
782
- this.updateSelectedOption(this.value);
783
- this.onModelChange(this.value);
784
- this.onChange.emit({
785
- originalEvent: event,
786
- value: this.value
787
- });
882
+ onEditableInput(event) {
883
+ const value = event.target.value;
884
+ this.searchValue = '';
885
+ const matched = this.searchOptions(event, value);
886
+ !matched && this.focusedOptionIndex.set(-1);
887
+ this.onModelChange(value);
888
+ this.updateModel(value, event);
788
889
  }
789
890
  /**
790
891
  * Displays the panel.
791
892
  * @group Method
792
893
  */
793
- show() {
894
+ show(isFocus) {
794
895
  this.overlayVisible = true;
896
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
897
+ this.focusedOptionIndex.set(focusedOptionIndex);
898
+ if (isFocus) {
899
+ DomHandler.focus(this.focusInputViewChild?.nativeElement);
900
+ }
795
901
  this.cd.markForCheck();
796
902
  }
797
903
  onOverlayAnimationStart(event) {
@@ -800,9 +906,9 @@ class Dropdown {
800
906
  this.virtualScroll && this.scroller?.setContentEl(this.itemsViewChild?.nativeElement);
801
907
  if (this.options && this.options.length) {
802
908
  if (this.virtualScroll) {
803
- const selectedIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
909
+ const selectedIndex = this.modelValue() ? this.focusedOptionIndex() : -1;
804
910
  if (selectedIndex !== -1) {
805
- this.scroller?.scrollToIndex(selectedIndex);
911
+ this.scroller?.scrollToIndex(0);
806
912
  }
807
913
  }
808
914
  else {
@@ -830,15 +936,24 @@ class Dropdown {
830
936
  * Hides the panel.
831
937
  * @group Method
832
938
  */
833
- hide() {
939
+ hide(isFocus) {
834
940
  this.overlayVisible = false;
941
+ this.focusedOptionIndex.set(-1);
835
942
  if (this.filter && this.resetFilterOnHide) {
836
943
  this.resetFilter();
837
944
  }
945
+ isFocus && DomHandler.focus(this.focusInputViewChild?.nativeElement);
838
946
  this.cd.markForCheck();
839
947
  }
840
948
  onInputFocus(event) {
949
+ if (this.disabled) {
950
+ // For ScreenReaders
951
+ return;
952
+ }
841
953
  this.focused = true;
954
+ const focusedOptionIndex = this.focusedOptionIndex() !== -1 ? this.focusedOptionIndex() : this.overlayVisible && this.autoOptionFocus ? this.findFirstFocusedOptionIndex() : -1;
955
+ this.focusedOptionIndex.set(focusedOptionIndex);
956
+ this.overlayVisible && this.scrollInView(this.focusedOptionIndex());
842
957
  this.onFocus.emit(event);
843
958
  }
844
959
  onInputBlur(event) {
@@ -849,331 +964,337 @@ class Dropdown {
849
964
  }
850
965
  this.preventModelTouched = false;
851
966
  }
852
- findPrevEnabledOption(index) {
853
- let prevEnabledOption;
854
- if (this.optionsToDisplay && this.optionsToDisplay.length) {
855
- for (let i = index - 1; 0 <= i; i--) {
856
- let option = this.optionsToDisplay[i];
857
- if (this.isOptionDisabled(option)) {
858
- continue;
859
- }
860
- else {
861
- prevEnabledOption = option;
862
- break;
863
- }
864
- }
865
- if (!prevEnabledOption) {
866
- for (let i = this.optionsToDisplay.length - 1; i >= index; i--) {
867
- let option = this.optionsToDisplay[i];
868
- if (this.isOptionDisabled(option)) {
869
- continue;
870
- }
871
- else {
872
- prevEnabledOption = option;
873
- break;
874
- }
875
- }
876
- }
877
- }
878
- return prevEnabledOption;
879
- }
880
- findNextEnabledOption(index) {
881
- let nextEnabledOption;
882
- if (this.optionsToDisplay && this.optionsToDisplay.length) {
883
- for (let i = index + 1; i < this.optionsToDisplay.length; i++) {
884
- let option = this.optionsToDisplay[i];
885
- if (this.isOptionDisabled(option)) {
886
- continue;
887
- }
888
- else {
889
- nextEnabledOption = option;
890
- break;
891
- }
892
- }
893
- if (!nextEnabledOption) {
894
- for (let i = 0; i < index; i++) {
895
- let option = this.optionsToDisplay[i];
896
- if (this.isOptionDisabled(option)) {
897
- continue;
898
- }
899
- else {
900
- nextEnabledOption = option;
901
- break;
902
- }
903
- }
904
- }
905
- }
906
- return nextEnabledOption;
907
- }
908
- onKeydown(event, search) {
909
- if (this.readonly || !this.optionsToDisplay || this.optionsToDisplay.length === null) {
967
+ onKeyDown(event, search) {
968
+ if (this.disabled || this.readonly) {
910
969
  return;
911
970
  }
912
- switch (event.which) {
971
+ switch (event.code) {
913
972
  //down
914
- case 40:
915
- if (!this.overlayVisible && event.altKey) {
916
- this.show();
917
- }
918
- else {
919
- if (this.group) {
920
- let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
921
- if (selectedItemIndex !== -1) {
922
- let nextItemIndex = selectedItemIndex.itemIndex + 1;
923
- if (nextItemIndex < this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex]).length) {
924
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex])[nextItemIndex]);
925
- this.selectedOptionUpdated = true;
926
- }
927
- else if (this.optionsToDisplay[selectedItemIndex.groupIndex + 1]) {
928
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex + 1])[0]);
929
- this.selectedOptionUpdated = true;
930
- }
931
- }
932
- else {
933
- if (this.optionsToDisplay && this.optionsToDisplay.length > 0) {
934
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[0])[0]);
935
- }
936
- }
937
- }
938
- else {
939
- let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
940
- let nextEnabledOption = this.findNextEnabledOption(selectedItemIndex);
941
- if (nextEnabledOption) {
942
- this.selectItem(event, nextEnabledOption);
943
- this.selectedOptionUpdated = true;
944
- }
945
- }
946
- }
947
- event.preventDefault();
973
+ case 'ArrowDown':
974
+ this.onArrowDownKey(event);
948
975
  break;
949
976
  //up
950
- case 38:
951
- if (this.group) {
952
- let selectedItemIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
953
- if (selectedItemIndex !== -1) {
954
- let prevItemIndex = selectedItemIndex.itemIndex - 1;
955
- if (prevItemIndex >= 0) {
956
- this.selectItem(event, this.getOptionGroupChildren(this.optionsToDisplay[selectedItemIndex.groupIndex])[prevItemIndex]);
957
- this.selectedOptionUpdated = true;
958
- }
959
- else if (prevItemIndex < 0) {
960
- let prevGroup = this.optionsToDisplay[selectedItemIndex.groupIndex - 1];
961
- if (prevGroup) {
962
- this.selectItem(event, this.getOptionGroupChildren(prevGroup)[this.getOptionGroupChildren(prevGroup).length - 1]);
963
- this.selectedOptionUpdated = true;
964
- }
965
- }
966
- }
967
- }
968
- else {
969
- let selectedItemIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
970
- let prevEnabledOption = this.findPrevEnabledOption(selectedItemIndex);
971
- if (prevEnabledOption) {
972
- this.selectItem(event, prevEnabledOption);
973
- this.selectedOptionUpdated = true;
974
- }
975
- }
976
- event.preventDefault();
977
+ case 'ArrowUp':
978
+ this.onArrowUpKey(event, this.editable);
979
+ break;
980
+ case 'ArrowLeft':
981
+ case 'ArrowRight':
982
+ this.onArrowLeftKey(event, this.editable);
983
+ break;
984
+ case 'Delete':
985
+ this.onDeleteKey(event);
986
+ break;
987
+ case 'Home':
988
+ this.onHomeKey(event, this.editable);
989
+ break;
990
+ case 'End':
991
+ this.onEndKey(event, this.editable);
992
+ break;
993
+ case 'PageDown':
994
+ this.onPageDownKey(event);
995
+ break;
996
+ case 'PageUp':
997
+ this.onPageUpKey(event);
977
998
  break;
978
999
  //space
979
- case 32:
980
- if (search) {
981
- if (!this.overlayVisible) {
982
- this.show();
983
- }
984
- else {
985
- this.hide();
986
- }
987
- event.preventDefault();
988
- }
1000
+ case 'Space':
1001
+ this.onSpaceKey(event, search);
989
1002
  break;
990
1003
  //enter
991
- case 13:
992
- if (this.overlayVisible && (!this.filter || (this.optionsToDisplay && this.optionsToDisplay.length > 0))) {
993
- this.hide();
994
- }
995
- else if (!this.overlayVisible) {
996
- this.show();
997
- }
998
- event.preventDefault();
1004
+ case 'Enter':
1005
+ case 'NumpadEnter':
1006
+ this.onEnterKey(event);
999
1007
  break;
1000
1008
  //escape and tab
1001
- case 27:
1002
- case 9:
1003
- this.hide();
1004
- event.preventDefault();
1009
+ case 'Escape':
1010
+ this.onEscapeKey(event);
1011
+ break;
1012
+ case 'Tab':
1013
+ this.onTabKey(event);
1014
+ break;
1015
+ case 'Backspace':
1016
+ this.onBackspaceKey(event, this.editable);
1017
+ break;
1018
+ case 'ShiftLeft':
1019
+ case 'ShiftRight':
1020
+ //NOOP
1005
1021
  break;
1006
- //search item based on keyboard input
1007
1022
  default:
1008
- if (search && !event.metaKey && event.which !== 17) {
1009
- this.search(event);
1023
+ if (!event.metaKey && ObjectUtils.isPrintableCharacter(event.key)) {
1024
+ !this.overlayVisible && this.show();
1025
+ !this.editable && this.searchOptions(event, event.key);
1010
1026
  }
1011
1027
  break;
1012
1028
  }
1013
1029
  }
1014
- search(event) {
1015
- if (this.searchTimeout) {
1016
- clearTimeout(this.searchTimeout);
1017
- }
1018
- const char = event.key;
1019
- this.previousSearchChar = this.currentSearchChar;
1020
- this.currentSearchChar = char;
1021
- if (this.previousSearchChar === this.currentSearchChar)
1022
- this.searchValue = this.currentSearchChar;
1023
- else
1024
- this.searchValue = this.searchValue ? this.searchValue + char : char;
1025
- let newOption;
1026
- if (this.group) {
1027
- let searchIndex = this.selectedOption ? this.findOptionGroupIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : { groupIndex: 0, itemIndex: 0 };
1028
- newOption = this.searchOptionWithinGroup(searchIndex);
1029
- }
1030
- else {
1031
- let searchIndex = this.selectedOption ? this.findOptionIndex(this.getOptionValue(this.selectedOption), this.optionsToDisplay) : -1;
1032
- newOption = this.searchOption(++searchIndex);
1033
- }
1034
- if (newOption && !this.isOptionDisabled(newOption)) {
1035
- this.selectItem(event, newOption);
1036
- this.selectedOptionUpdated = true;
1030
+ onFilterKeyDown(event) {
1031
+ switch (event.code) {
1032
+ case 'ArrowDown':
1033
+ this.onArrowDownKey(event);
1034
+ break;
1035
+ case 'ArrowUp':
1036
+ this.onArrowUpKey(event, true);
1037
+ break;
1038
+ case 'ArrowLeft':
1039
+ case 'ArrowRight':
1040
+ this.onArrowLeftKey(event, true);
1041
+ break;
1042
+ case 'Home':
1043
+ this.onHomeKey(event, true);
1044
+ break;
1045
+ case 'End':
1046
+ this.onEndKey(event, true);
1047
+ break;
1048
+ case 'Enter':
1049
+ this.onEnterKey(event);
1050
+ break;
1051
+ case 'Escape':
1052
+ this.onEscapeKey(event);
1053
+ break;
1054
+ case 'Tab':
1055
+ this.onTabKey(event, true);
1056
+ break;
1057
+ default:
1058
+ break;
1037
1059
  }
1038
- this.searchTimeout = setTimeout(() => {
1039
- this.searchValue = null;
1040
- }, 250);
1041
- }
1042
- searchOption(index) {
1043
- let option;
1044
- if (this.searchValue) {
1045
- option = this.searchOptionInRange(index, this.optionsToDisplay.length);
1046
- if (!option) {
1047
- option = this.searchOptionInRange(0, index);
1060
+ }
1061
+ onFilterBlur(event) {
1062
+ this.focusedOptionIndex.set(-1);
1063
+ }
1064
+ onArrowDownKey(event) {
1065
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findNextOptionIndex(this.focusedOptionIndex()) : this.findFirstFocusedOptionIndex();
1066
+ this.changeFocusedOptionIndex(event, optionIndex);
1067
+ !this.overlayVisible && this.show();
1068
+ event.preventDefault();
1069
+ }
1070
+ changeFocusedOptionIndex(event, index) {
1071
+ if (this.focusedOptionIndex() !== index) {
1072
+ this.focusedOptionIndex.set(index);
1073
+ this.scrollInView();
1074
+ if (this.selectOnFocus) {
1075
+ const option = this.visibleOptions()[index];
1076
+ this.onOptionSelect(event, option, false);
1048
1077
  }
1049
1078
  }
1050
- return option;
1051
- }
1052
- searchOptionInRange(start, end) {
1053
- for (let i = start; i < end; i++) {
1054
- let opt = this.optionsToDisplay[i];
1055
- if (this.getOptionLabel(opt)
1056
- .toLocaleLowerCase(this.filterLocale)
1057
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1058
- !this.isOptionDisabled(opt)) {
1059
- return opt;
1079
+ }
1080
+ get virtualScrollerDisabled() {
1081
+ return !this.virtualScroll;
1082
+ }
1083
+ scrollInView(index = -1) {
1084
+ const id = index !== -1 ? `${this.id}_${index}` : this.focusedOptionId;
1085
+ if (this.itemsViewChild && this.itemsViewChild.nativeElement) {
1086
+ const element = DomHandler.findSingle(this.itemsViewChild.nativeElement, `li[id="${id}"]`);
1087
+ if (element) {
1088
+ element.scrollIntoView && element.scrollIntoView({ block: 'nearest', inline: 'start' });
1060
1089
  }
1061
- }
1062
- return null;
1063
- }
1064
- searchOptionWithinGroup(index) {
1065
- let option;
1066
- if (this.searchValue) {
1067
- if (this.optionsToDisplay) {
1068
- for (let i = index.groupIndex; i < this.optionsToDisplay.length; i++) {
1069
- for (let j = index.groupIndex === i ? index.itemIndex + 1 : 0; j < this.getOptionGroupChildren(this.optionsToDisplay[i]).length; j++) {
1070
- let opt = this.getOptionGroupChildren(this.optionsToDisplay[i])[j];
1071
- if (this.getOptionLabel(opt)
1072
- .toLocaleLowerCase(this.filterLocale)
1073
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1074
- !this.isOptionDisabled(opt)) {
1075
- return opt;
1076
- }
1077
- }
1078
- }
1079
- if (!option) {
1080
- for (let i = 0; i <= index.groupIndex; i++) {
1081
- for (let j = 0; j < (index.groupIndex === i ? index.itemIndex : this.getOptionGroupChildren(this.optionsToDisplay[i]).length); j++) {
1082
- let opt = this.getOptionGroupChildren(this.optionsToDisplay[i])[j];
1083
- if (this.getOptionLabel(opt)
1084
- .toLocaleLowerCase(this.filterLocale)
1085
- .startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale)) &&
1086
- !this.isOptionDisabled(opt)) {
1087
- return opt;
1088
- }
1089
- }
1090
- }
1091
- }
1090
+ else if (!this.virtualScrollerDisabled) {
1091
+ setTimeout(() => {
1092
+ this.virtualScroll && this.scroller?.scrollToIndex(index !== -1 ? index : this.focusedOptionIndex());
1093
+ }, 0);
1092
1094
  }
1093
1095
  }
1094
- return null;
1095
- }
1096
- findOptionIndex(val, opts) {
1097
- let index = -1;
1098
- if (opts) {
1099
- for (let i = 0; i < opts.length; i++) {
1100
- if ((val == null && this.getOptionValue(opts[i]) == null) || ObjectUtils.equals(val, this.getOptionValue(opts[i]), this.dataKey)) {
1101
- index = i;
1102
- break;
1103
- }
1096
+ }
1097
+ get focusedOptionId() {
1098
+ return this.focusedOptionIndex() !== -1 ? `${this.id}_${this.focusedOptionIndex()}` : null;
1099
+ }
1100
+ hasSelectedOption() {
1101
+ return ObjectUtils.isNotEmpty(this.modelValue());
1102
+ }
1103
+ isValidSelectedOption(option) {
1104
+ return this.isValidOption(option) && this.isSelected(option);
1105
+ }
1106
+ equalityKey() {
1107
+ return this.optionValue ? null : this.dataKey;
1108
+ }
1109
+ findFirstFocusedOptionIndex() {
1110
+ const selectedIndex = this.findSelectedOptionIndex();
1111
+ return selectedIndex < 0 ? this.findFirstOptionIndex() : selectedIndex;
1112
+ }
1113
+ findFirstOptionIndex() {
1114
+ return this.visibleOptions().findIndex((option) => this.isValidOption(option));
1115
+ }
1116
+ findSelectedOptionIndex() {
1117
+ return this.hasSelectedOption() ? this.visibleOptions().findIndex((option) => this.isValidSelectedOption(option)) : -1;
1118
+ }
1119
+ findNextOptionIndex(index) {
1120
+ const matchedOptionIndex = index < this.visibleOptions().length - 1
1121
+ ? this.visibleOptions()
1122
+ .slice(index + 1)
1123
+ .findIndex((option) => this.isValidOption(option))
1124
+ : -1;
1125
+ return matchedOptionIndex > -1 ? matchedOptionIndex + index + 1 : index;
1126
+ }
1127
+ findPrevOptionIndex(index) {
1128
+ const matchedOptionIndex = index > 0 ? ObjectUtils.findLastIndex(this.visibleOptions().slice(0, index), (option) => this.isValidOption(option)) : -1;
1129
+ return matchedOptionIndex > -1 ? matchedOptionIndex : index;
1130
+ }
1131
+ findLastOptionIndex() {
1132
+ return ObjectUtils.findLastIndex(this.visibleOptions(), (option) => this.isValidOption(option));
1133
+ }
1134
+ findLastFocusedOptionIndex() {
1135
+ const selectedIndex = this.findSelectedOptionIndex();
1136
+ return selectedIndex < 0 ? this.findLastOptionIndex() : selectedIndex;
1137
+ }
1138
+ isValidOption(option) {
1139
+ return option && !(this.isOptionDisabled(option) || this.isOptionGroup(option));
1140
+ }
1141
+ isOptionGroup(option) {
1142
+ return this.optionGroupLabel && option.optionGroup && option.group;
1143
+ }
1144
+ onArrowUpKey(event, pressedInInputText = false) {
1145
+ if (event.altKey && !pressedInInputText) {
1146
+ if (this.focusedOptionIndex() !== -1) {
1147
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1148
+ this.onOptionSelect(event, option);
1104
1149
  }
1150
+ this.overlayVisible && this.hide();
1151
+ event.preventDefault();
1105
1152
  }
1106
- return index;
1107
- }
1108
- findOptionGroupIndex(val, opts) {
1109
- let groupIndex, itemIndex;
1110
- if (opts) {
1111
- for (let i = 0; i < opts.length; i++) {
1112
- groupIndex = i;
1113
- itemIndex = this.findOptionIndex(val, this.getOptionGroupChildren(opts[i]));
1114
- if (itemIndex !== -1) {
1115
- break;
1116
- }
1117
- }
1153
+ else {
1154
+ const optionIndex = this.focusedOptionIndex() !== -1 ? this.findPrevOptionIndex(this.focusedOptionIndex()) : this.findLastFocusedOptionIndex();
1155
+ this.changeFocusedOptionIndex(event, optionIndex);
1156
+ !this.overlayVisible && this.show();
1157
+ event.preventDefault();
1118
1158
  }
1119
- if (itemIndex !== -1) {
1120
- return { groupIndex: groupIndex, itemIndex: itemIndex };
1159
+ }
1160
+ onArrowLeftKey(event, pressedInInputText = false) {
1161
+ pressedInInputText && this.focusedOptionIndex.set(-1);
1162
+ }
1163
+ onDeleteKey(event) {
1164
+ if (this.showClear) {
1165
+ this.clear(event);
1166
+ event.preventDefault();
1167
+ }
1168
+ }
1169
+ onHomeKey(event, pressedInInputText = false) {
1170
+ if (pressedInInputText) {
1171
+ event.currentTarget.setSelectionRange(0, 0);
1172
+ this.focusedOptionIndex.set(-1);
1121
1173
  }
1122
1174
  else {
1123
- return -1;
1175
+ this.changeFocusedOptionIndex(event, this.findFirstOptionIndex());
1176
+ !this.overlayVisible && this.show();
1124
1177
  }
1125
- }
1126
- findOption(val, opts, inGroup) {
1127
- if (this.group && !inGroup) {
1128
- let opt;
1129
- if (opts && opts.length) {
1130
- for (let optgroup of opts) {
1131
- opt = this.findOption(val, this.getOptionGroupChildren(optgroup), true);
1132
- if (opt) {
1133
- break;
1134
- }
1135
- }
1136
- }
1137
- return opt;
1178
+ event.preventDefault();
1179
+ }
1180
+ onEndKey(event, pressedInInputText = false) {
1181
+ if (pressedInInputText) {
1182
+ const target = event.currentTarget;
1183
+ const len = target.value.length;
1184
+ target.setSelectionRange(len, len);
1185
+ this.focusedOptionIndex.set(-1);
1138
1186
  }
1139
1187
  else {
1140
- let index = this.findOptionIndex(val, opts);
1141
- return index != -1 ? opts[index] : null;
1188
+ this.changeFocusedOptionIndex(event, this.findLastOptionIndex());
1189
+ !this.overlayVisible && this.show();
1142
1190
  }
1191
+ event.preventDefault();
1143
1192
  }
1144
- onFilterInputChange(event) {
1145
- let inputValue = event.target.value?.trim();
1146
- if (inputValue && inputValue.length) {
1147
- this._filterValue = inputValue;
1148
- this.activateFilter();
1193
+ onPageDownKey(event) {
1194
+ this.scrollInView(this.visibleOptions().length - 1);
1195
+ event.preventDefault();
1196
+ }
1197
+ onPageUpKey(event) {
1198
+ this.scrollInView(0);
1199
+ event.preventDefault();
1200
+ }
1201
+ onSpaceKey(event, pressedInInputText = false) {
1202
+ !pressedInInputText && this.onEnterKey(event);
1203
+ }
1204
+ onEnterKey(event) {
1205
+ if (!this.overlayVisible) {
1206
+ this.onArrowDownKey(event);
1149
1207
  }
1150
1208
  else {
1151
- this._filterValue = null;
1152
- this.optionsToDisplay = this.options;
1209
+ if (this.focusedOptionIndex() !== -1) {
1210
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1211
+ this.onOptionSelect(event, option);
1212
+ }
1213
+ this.hide();
1153
1214
  }
1154
- this.virtualScroll && this.scroller?.scrollToIndex(0);
1155
- this.optionsChanged = true;
1156
- this.onFilter.emit({ originalEvent: event, filter: this._filterValue });
1215
+ event.preventDefault();
1157
1216
  }
1158
- activateFilter() {
1159
- let searchFields = (this.filterBy || this.optionLabel || 'label').split(',');
1160
- if (this.options && this.options.length) {
1161
- if (this.group) {
1162
- let filteredGroups = [];
1163
- for (let optgroup of this.options) {
1164
- let filteredSubOptions = this.filterService.filter(this.getOptionGroupChildren(optgroup), searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
1165
- if (filteredSubOptions && filteredSubOptions.length) {
1166
- filteredGroups.push({ ...optgroup, ...{ [this.optionGroupChildren]: filteredSubOptions } });
1167
- }
1168
- }
1169
- this.optionsToDisplay = filteredGroups;
1217
+ onEscapeKey(event) {
1218
+ this.overlayVisible && this.hide(true);
1219
+ event.preventDefault();
1220
+ }
1221
+ onTabKey(event, pressedInInputText = false) {
1222
+ if (!pressedInInputText) {
1223
+ if (this.overlayVisible && this.hasFocusableElements()) {
1224
+ DomHandler.focus(this.firstHiddenFocusableElementOnOverlay.nativeElement);
1225
+ event.preventDefault();
1170
1226
  }
1171
1227
  else {
1172
- this.optionsToDisplay = this.filterService.filter(this.options, searchFields, this.filterValue, this.filterMatchMode, this.filterLocale);
1228
+ if (this.focusedOptionIndex() !== -1) {
1229
+ const option = this.visibleOptions()[this.focusedOptionIndex()];
1230
+ this.onOptionSelect(event, option);
1231
+ }
1232
+ this.overlayVisible && this.hide(this.filter);
1173
1233
  }
1174
- this.optionsChanged = true;
1175
1234
  }
1176
1235
  }
1236
+ onFirstHiddenFocus(event) {
1237
+ const focusableEl = event.relatedTarget === this.focusInputViewChild.nativeElement ? DomHandler.getFirstFocusableElement(this.overlayViewChild.el.nativeElement, ':not(.p-hidden-focusable)') : this.focusInputViewChild.nativeElement;
1238
+ DomHandler.focus(focusableEl);
1239
+ }
1240
+ hasFocusableElements() {
1241
+ return DomHandler.getFocusableElements(this.overlayViewChild.overlayViewChild.nativeElement, ':not(.p-hidden-focusable)').length > 0;
1242
+ }
1243
+ onBackspaceKey(event, pressedInInputText = false) {
1244
+ if (pressedInInputText) {
1245
+ !this.overlayVisible && this.show();
1246
+ }
1247
+ }
1248
+ searchFields() {
1249
+ return this.filterFields || [this.optionLabel];
1250
+ }
1251
+ searchOptions(event, char) {
1252
+ this.searchValue = (this.searchValue || '') + char;
1253
+ let optionIndex = -1;
1254
+ let matched = false;
1255
+ if (this.focusedOptionIndex() !== -1) {
1256
+ optionIndex = this.visibleOptions()
1257
+ .slice(this.focusedOptionIndex())
1258
+ .findIndex((option) => this.isOptionMatched(option));
1259
+ optionIndex =
1260
+ optionIndex === -1
1261
+ ? this.visibleOptions()
1262
+ .slice(0, this.focusedOptionIndex())
1263
+ .findIndex((option) => this.isOptionMatched(option))
1264
+ : optionIndex + this.focusedOptionIndex();
1265
+ }
1266
+ else {
1267
+ optionIndex = this.visibleOptions().findIndex((option) => this.isOptionMatched(option));
1268
+ }
1269
+ if (optionIndex !== -1) {
1270
+ matched = true;
1271
+ }
1272
+ if (optionIndex === -1 && this.focusedOptionIndex() === -1) {
1273
+ optionIndex = this.findFirstFocusedOptionIndex();
1274
+ }
1275
+ if (optionIndex !== -1) {
1276
+ this.changeFocusedOptionIndex(event, optionIndex);
1277
+ }
1278
+ if (this.searchTimeout) {
1279
+ clearTimeout(this.searchTimeout);
1280
+ }
1281
+ this.searchTimeout = setTimeout(() => {
1282
+ this.searchValue = '';
1283
+ this.searchTimeout = null;
1284
+ }, 500);
1285
+ return matched;
1286
+ }
1287
+ isOptionMatched(option) {
1288
+ return this.isValidOption(option) && this.getOptionLabel(option).toLocaleLowerCase(this.filterLocale).startsWith(this.searchValue.toLocaleLowerCase(this.filterLocale));
1289
+ }
1290
+ onFilterInputChange(event) {
1291
+ let value = event.target.value?.trim();
1292
+ this._filterValue.set(value);
1293
+ this.focusedOptionIndex.set(-1);
1294
+ this.onFilter.emit({ originalEvent: event, filter: this._filterValue() });
1295
+ !this.virtualScrollerDisabled && this.scroller.scrollToIndex(0);
1296
+ this.cd.markForCheck();
1297
+ }
1177
1298
  applyFocus() {
1178
1299
  if (this.editable)
1179
1300
  DomHandler.findSingle(this.el.nativeElement, '.p-dropdown-label.p-inputtext').focus();
@@ -1188,84 +1309,66 @@ class Dropdown {
1188
1309
  this.applyFocus();
1189
1310
  }
1190
1311
  clear(event) {
1191
- this.value = null;
1192
- this.onModelChange(this.value);
1193
- this.onChange.emit({
1194
- originalEvent: event,
1195
- value: this.value
1196
- });
1197
- this.updateSelectedOption(this.value);
1312
+ this.updateModel(null, event);
1198
1313
  this.updateEditableLabel();
1199
1314
  this.onClear.emit(event);
1200
1315
  }
1201
1316
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: Dropdown, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i3.FilterService }, { token: i3.PrimeNGConfig }], target: i0.ɵɵFactoryTarget.Component });
1202
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: Dropdown, selector: "p-dropdown", inputs: { scrollHeight: "scrollHeight", filter: "filter", name: "name", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", readonly: "readonly", required: "required", editable: "editable", appendTo: "appendTo", tabindex: "tabindex", placeholder: "placeholder", filterPlaceholder: "filterPlaceholder", filterLocale: "filterLocale", inputId: "inputId", dataKey: "dataKey", filterBy: "filterBy", autofocus: "autofocus", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", autoDisplayFirst: "autoDisplayFirst", group: "group", showClear: "showClear", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", filterMatchMode: "filterMatchMode", maxlength: "maxlength", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", autofocusFilter: "autofocusFilter", disabled: "disabled", itemSize: "itemSize", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", filterValue: "filterValue", options: "options" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onShow: "onShow", onHide: "onHide", onClear: "onClear", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focused || overlayVisible" }, classAttribute: "p-element p-inputwrapper" }, providers: [DROPDOWN_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true }, { propertyName: "accessibleViewChild", first: true, predicate: ["in"], descendants: true }, { propertyName: "editableInputViewChild", first: true, predicate: ["editableInput"], 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: `
1203
- <div
1204
- #container
1205
- [ngClass]="{ 'p-dropdown p-component': true, 'p-disabled': disabled, 'p-dropdown-open': overlayVisible, 'p-focus': focused, 'p-dropdown-clearable': showClear && !disabled }"
1206
- (click)="onMouseclick($event)"
1207
- [ngStyle]="style"
1208
- [class]="styleClass"
1209
- >
1210
- <div class="p-hidden-accessible">
1211
- <input
1212
- #in
1213
- [attr.id]="inputId"
1214
- type="text"
1215
- readonly
1216
- (focus)="onInputFocus($event)"
1217
- aria-haspopup="listbox"
1218
- [attr.placeholder]="placeholder"
1219
- aria-haspopup="listbox"
1220
- [attr.aria-label]="ariaLabel"
1221
- [attr.aria-expanded]="false"
1222
- [attr.aria-labelledby]="ariaLabelledBy"
1223
- (blur)="onInputBlur($event)"
1224
- (keydown)="onKeydown($event, true)"
1225
- [disabled]="disabled"
1226
- [attr.tabindex]="tabindex"
1227
- pAutoFocus
1228
- [autofocus]="autofocus"
1229
- [attr.aria-activedescendant]="overlayVisible ? labelId : null"
1230
- role="combobox"
1231
- />
1232
- </div>
1317
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.0.2", type: Dropdown, selector: "p-dropdown", inputs: { id: "id", scrollHeight: "scrollHeight", filter: "filter", name: "name", style: "style", panelStyle: "panelStyle", styleClass: "styleClass", panelStyleClass: "panelStyleClass", readonly: "readonly", required: "required", editable: "editable", appendTo: "appendTo", tabindex: "tabindex", placeholder: "placeholder", filterPlaceholder: "filterPlaceholder", filterLocale: "filterLocale", inputId: "inputId", dataKey: "dataKey", filterBy: "filterBy", filterFields: "filterFields", autofocus: "autofocus", resetFilterOnHide: "resetFilterOnHide", dropdownIcon: "dropdownIcon", optionLabel: "optionLabel", optionValue: "optionValue", optionDisabled: "optionDisabled", optionGroupLabel: "optionGroupLabel", optionGroupChildren: "optionGroupChildren", autoDisplayFirst: "autoDisplayFirst", group: "group", showClear: "showClear", emptyFilterMessage: "emptyFilterMessage", emptyMessage: "emptyMessage", lazy: "lazy", virtualScroll: "virtualScroll", virtualScrollItemSize: "virtualScrollItemSize", virtualScrollOptions: "virtualScrollOptions", overlayOptions: "overlayOptions", ariaFilterLabel: "ariaFilterLabel", ariaLabel: "ariaLabel", ariaLabelledBy: "ariaLabelledBy", filterMatchMode: "filterMatchMode", maxlength: "maxlength", tooltip: "tooltip", tooltipPosition: "tooltipPosition", tooltipPositionStyle: "tooltipPositionStyle", tooltipStyleClass: "tooltipStyleClass", focusOnHover: "focusOnHover", selectOnFocus: "selectOnFocus", autoOptionFocus: "autoOptionFocus", autofocusFilter: "autofocusFilter", disabled: "disabled", itemSize: "itemSize", autoZIndex: "autoZIndex", baseZIndex: "baseZIndex", showTransitionOptions: "showTransitionOptions", hideTransitionOptions: "hideTransitionOptions", filterValue: "filterValue", options: "options" }, outputs: { onChange: "onChange", onFilter: "onFilter", onFocus: "onFocus", onBlur: "onBlur", onClick: "onClick", onShow: "onShow", onHide: "onHide", onClear: "onClear", onLazyLoad: "onLazyLoad" }, host: { properties: { "class.p-inputwrapper-filled": "filled", "class.p-inputwrapper-focus": "focused || overlayVisible" }, classAttribute: "p-element p-inputwrapper" }, providers: [DROPDOWN_VALUE_ACCESSOR], queries: [{ propertyName: "templates", predicate: PrimeTemplate }], viewQueries: [{ propertyName: "containerViewChild", first: true, predicate: ["container"], descendants: true }, { propertyName: "filterViewChild", first: true, predicate: ["filter"], descendants: true }, { propertyName: "focusInputViewChild", first: true, predicate: ["focusInput"], descendants: true }, { propertyName: "editableInputViewChild", first: true, predicate: ["editableInput"], 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 }, { propertyName: "firstHiddenFocusableElementOnOverlay", first: true, predicate: ["firstHiddenFocusableElementOnOverlay"], descendants: true }], ngImport: i0, template: `
1318
+ <div #container [attr.id]="id" [ngClass]="containerClass" (click)="onContainerClick($event)" [ngStyle]="style" [class]="styleClass">
1233
1319
  <span
1234
- [attr.id]="labelId"
1235
- [ngClass]="{ 'p-dropdown-label p-inputtext': true, 'p-dropdown-label-empty': label == null || label.length === 0 }"
1236
- *ngIf="!editable && label != null"
1320
+ #focusInput
1321
+ [ngClass]="inputClass"
1322
+ *ngIf="!editable"
1237
1323
  [pTooltip]="tooltip"
1238
1324
  [tooltipPosition]="tooltipPosition"
1239
1325
  [positionStyle]="tooltipPositionStyle"
1240
1326
  [tooltipStyleClass]="tooltipStyleClass"
1327
+ [attr.aria-disabled]="disabled"
1328
+ [attr.id]="inputId"
1329
+ role="combobox"
1330
+ [attr.aria-label]="ariaLabel"
1331
+ [attr.aria-labelledby]="ariaLabelledBy"
1332
+ [attr.aria-haspopup]="'listbox'"
1333
+ [attr.aria-expanded]="overlayVisible"
1334
+ [attr.aria-controls]="id + '_list'"
1335
+ [attr.tabindex]="!disabled ? tabindex : -1"
1336
+ pAutoFocus
1337
+ [autofocus]="autofocus"
1338
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1339
+ (focus)="onInputFocus($event)"
1340
+ (blur)="onInputBlur($event)"
1341
+ (keydown)="onKeyDown($event)"
1241
1342
  >
1242
- <ng-container *ngIf="!selectedItemTemplate">{{ label || 'empty' }}</ng-container>
1243
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: selectedOption }"></ng-container>
1343
+ <ng-container *ngIf="!selectedItemTemplate; else defaultPlaceholder">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() || 'empty' }}</ng-container>
1344
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: modelValue() }"></ng-container>
1345
+ <ng-template #defaultPlaceholder>
1346
+ <span *ngIf="label() === placeholder || (label() && !placeholder)">{{ label() === 'p-emptylabel' ? '&nbsp;' : placeholder }}</span>
1347
+ </ng-template>
1244
1348
  </span>
1245
- <span [ngClass]="{ 'p-dropdown-label p-inputtext p-placeholder': true, 'p-dropdown-label-empty': placeholder == null || placeholder.length === 0 }" *ngIf="!editable && label == null">{{ placeholder || 'empty' }}</span>
1246
1349
  <input
1350
+ *ngIf="editable"
1247
1351
  #editableInput
1248
1352
  type="text"
1249
1353
  [attr.maxlength]="maxlength"
1250
- class="p-dropdown-label p-inputtext"
1251
- *ngIf="editable"
1354
+ [ngClass]="inputClass"
1252
1355
  [disabled]="disabled"
1253
- [attr.placeholder]="placeholder"
1254
1356
  aria-haspopup="listbox"
1357
+ [attr.placeholder]="placeholder"
1255
1358
  [attr.aria-expanded]="overlayVisible"
1256
- (input)="onEditableInputChange($event)"
1257
- (focus)="onEditableInputFocus($event)"
1359
+ (input)="onEditableInput($event)"
1360
+ (keydown)="onKeyDown($event)"
1361
+ (focus)="onInputFocus($event)"
1258
1362
  (blur)="onInputBlur($event)"
1259
1363
  />
1260
-
1261
1364
  <ng-container *ngIf="isVisibleClearIcon">
1262
- <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" />
1263
- <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate">
1365
+ <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" [attr.data-pc-section]="'clearicon'" />
1366
+ <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate" [attr.data-pc-section]="'clearicon'">
1264
1367
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1265
1368
  </span>
1266
1369
  </ng-container>
1267
1370
 
1268
- <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible">
1371
+ <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" [attr.data-pc-section]="'trigger'">
1269
1372
  <ng-container *ngIf="!dropdownIconTemplate">
1270
1373
  <span class="p-dropdown-trigger-icon" *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1271
1374
  <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-dropdown-trigger-icon'" />
@@ -1290,6 +1393,15 @@ class Dropdown {
1290
1393
  >
1291
1394
  <ng-template pTemplate="content">
1292
1395
  <div [ngClass]="'p-dropdown-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1396
+ <span
1397
+ #firstHiddenFocusableElementOnOverlay
1398
+ role="presentation"
1399
+ [attr.aria-hidden]="true"
1400
+ class="p-hidden-accessible p-hidden-focusable"
1401
+ [attr.tabindex]="0"
1402
+ (focus)="onFirstHiddenFocus($event)"
1403
+ [attr.data-p-hidden-focusable]="true"
1404
+ ></span>
1293
1405
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1294
1406
  <div class="p-dropdown-header" *ngIf="filter" (click)="$event.stopPropagation()">
1295
1407
  <ng-container *ngIf="filterTemplate; else builtInFilterElement">
@@ -1301,14 +1413,15 @@ class Dropdown {
1301
1413
  #filter
1302
1414
  type="text"
1303
1415
  autocomplete="off"
1304
- [value]="filterValue || ''"
1416
+ [value]="_filterValue() || ''"
1305
1417
  class="p-dropdown-filter p-inputtext p-component"
1306
1418
  [attr.placeholder]="filterPlaceholder"
1307
- (keydown.enter)="$event.preventDefault()"
1308
- (keydown)="onKeydown($event, false)"
1419
+ [attr.aria-owns]="id + '_list'"
1309
1420
  (input)="onFilterInputChange($event)"
1310
1421
  [attr.aria-label]="ariaFilterLabel"
1311
- [attr.aria-activedescendant]="overlayVisible ? 'p-highlighted-option' : labelId"
1422
+ [attr.aria-activedescendant]="focusedOptionId"
1423
+ (keydown)="onFilterKeyDown($event)"
1424
+ (blur)="onFilterBlur($event)"
1312
1425
  />
1313
1426
  <SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-dropdown-filter-icon'" />
1314
1427
  <span *ngIf="filterIconTemplate" class="p-dropdown-filter-icon">
@@ -1321,7 +1434,7 @@ class Dropdown {
1321
1434
  <p-scroller
1322
1435
  *ngIf="virtualScroll"
1323
1436
  #scroller
1324
- [items]="optionsToDisplay"
1437
+ [items]="visibleOptions()"
1325
1438
  [style]="{ height: scrollHeight }"
1326
1439
  [itemSize]="virtualScrollItemSize || _itemSize"
1327
1440
  [autoSize]="true"
@@ -1339,35 +1452,35 @@ class Dropdown {
1339
1452
  </ng-container>
1340
1453
  </p-scroller>
1341
1454
  <ng-container *ngIf="!virtualScroll">
1342
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToDisplay, options: {} }"></ng-container>
1455
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1343
1456
  </ng-container>
1344
1457
 
1345
1458
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1346
- <ul #items [attr.id]="listId" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1347
- <ng-container *ngIf="group">
1348
- <ng-template ngFor let-optgroup [ngForOf]="items">
1349
- <li class="p-dropdown-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1350
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1351
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1459
+ <ul #items [attr.id]="id + '_list'" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1460
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1461
+ <ng-container *ngIf="option.group">
1462
+ <li class="p-dropdown-item-group" [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1463
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1464
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1352
1465
  </li>
1353
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup), selectedOption: selectedOption }"></ng-container>
1354
- </ng-template>
1355
- </ng-container>
1356
- <ng-container *ngIf="!group">
1357
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items, selectedOption: selectedOption }"></ng-container>
1358
- </ng-container>
1359
- <ng-template #itemslist let-options let-selectedOption="selectedOption">
1360
- <ng-template ngFor let-option let-i="index" [ngForOf]="options">
1466
+ </ng-container>
1467
+ <ng-container *ngIf="!option.group">
1361
1468
  <p-dropdownItem
1469
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1362
1470
  [option]="option"
1363
- [selected]="selectedOption == option"
1471
+ [selected]="isSelected(option)"
1364
1472
  [label]="getOptionLabel(option)"
1365
1473
  [disabled]="isOptionDisabled(option)"
1366
- (onClick)="onItemClick($event)"
1367
1474
  [template]="itemTemplate"
1475
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1476
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1477
+ [ariaSetSize]="ariaSetSize"
1478
+ (onClick)="onOptionSelect($event, option)"
1479
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1368
1480
  ></p-dropdownItem>
1369
- </ng-template>
1481
+ </ng-container>
1370
1482
  </ng-template>
1483
+
1371
1484
  <li *ngIf="filterValue && isEmpty()" class="p-dropdown-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1372
1485
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1373
1486
  {{ emptyFilterMessageLabel }}
@@ -1388,77 +1501,65 @@ class Dropdown {
1388
1501
  </ng-template>
1389
1502
  </p-overlay>
1390
1503
  </div>
1391
- `, isInline: true, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;visibility:hidden}input.p-dropdown-label{cursor:default}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i1.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgTemplateOutlet; }), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgStyle; }), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(function () { return i4.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 i3.PrimeTemplate; }), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i5.Tooltip; }), selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { 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 TimesIcon; }), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(function () { return ChevronDownIcon; }), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return DropdownItem; }), selector: "p-dropdownItem", inputs: ["option", "selected", "label", "disabled", "visible", "itemSize", "template"], outputs: ["onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1504
+ `, isInline: true, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;opacity:0}input.p-dropdown-label{cursor:default}.p-dropdown .p-dropdown-panel{min-width:100%}.p-dropdown-panel{position:absolute;top:0;left:0}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-item-group{cursor:auto}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return i1.NgClass; }), selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgForOf; }), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgIf; }), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgTemplateOutlet; }), selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i0.forwardRef(function () { return i1.NgStyle; }), selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i0.forwardRef(function () { return i4.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 i3.PrimeTemplate; }), selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i0.forwardRef(function () { return i5.Tooltip; }), selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { 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 TimesIcon; }), selector: "TimesIcon" }, { kind: "component", type: i0.forwardRef(function () { return ChevronDownIcon; }), selector: "ChevronDownIcon" }, { kind: "component", type: i0.forwardRef(function () { return SearchIcon; }), selector: "SearchIcon" }, { kind: "component", type: i0.forwardRef(function () { return DropdownItem; }), selector: "p-dropdownItem", inputs: ["id", "option", "selected", "focused", "label", "disabled", "visible", "itemSize", "ariaPosInset", "ariaSetSize", "template"], outputs: ["onClick", "onMouseEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1392
1505
  }
1393
1506
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImport: i0, type: Dropdown, decorators: [{
1394
1507
  type: Component,
1395
1508
  args: [{ selector: 'p-dropdown', template: `
1396
- <div
1397
- #container
1398
- [ngClass]="{ 'p-dropdown p-component': true, 'p-disabled': disabled, 'p-dropdown-open': overlayVisible, 'p-focus': focused, 'p-dropdown-clearable': showClear && !disabled }"
1399
- (click)="onMouseclick($event)"
1400
- [ngStyle]="style"
1401
- [class]="styleClass"
1402
- >
1403
- <div class="p-hidden-accessible">
1404
- <input
1405
- #in
1406
- [attr.id]="inputId"
1407
- type="text"
1408
- readonly
1409
- (focus)="onInputFocus($event)"
1410
- aria-haspopup="listbox"
1411
- [attr.placeholder]="placeholder"
1412
- aria-haspopup="listbox"
1413
- [attr.aria-label]="ariaLabel"
1414
- [attr.aria-expanded]="false"
1415
- [attr.aria-labelledby]="ariaLabelledBy"
1416
- (blur)="onInputBlur($event)"
1417
- (keydown)="onKeydown($event, true)"
1418
- [disabled]="disabled"
1419
- [attr.tabindex]="tabindex"
1420
- pAutoFocus
1421
- [autofocus]="autofocus"
1422
- [attr.aria-activedescendant]="overlayVisible ? labelId : null"
1423
- role="combobox"
1424
- />
1425
- </div>
1509
+ <div #container [attr.id]="id" [ngClass]="containerClass" (click)="onContainerClick($event)" [ngStyle]="style" [class]="styleClass">
1426
1510
  <span
1427
- [attr.id]="labelId"
1428
- [ngClass]="{ 'p-dropdown-label p-inputtext': true, 'p-dropdown-label-empty': label == null || label.length === 0 }"
1429
- *ngIf="!editable && label != null"
1511
+ #focusInput
1512
+ [ngClass]="inputClass"
1513
+ *ngIf="!editable"
1430
1514
  [pTooltip]="tooltip"
1431
1515
  [tooltipPosition]="tooltipPosition"
1432
1516
  [positionStyle]="tooltipPositionStyle"
1433
1517
  [tooltipStyleClass]="tooltipStyleClass"
1518
+ [attr.aria-disabled]="disabled"
1519
+ [attr.id]="inputId"
1520
+ role="combobox"
1521
+ [attr.aria-label]="ariaLabel"
1522
+ [attr.aria-labelledby]="ariaLabelledBy"
1523
+ [attr.aria-haspopup]="'listbox'"
1524
+ [attr.aria-expanded]="overlayVisible"
1525
+ [attr.aria-controls]="id + '_list'"
1526
+ [attr.tabindex]="!disabled ? tabindex : -1"
1527
+ pAutoFocus
1528
+ [autofocus]="autofocus"
1529
+ [attr.aria-activedescendant]="focused ? focusedOptionId : undefined"
1530
+ (focus)="onInputFocus($event)"
1531
+ (blur)="onInputBlur($event)"
1532
+ (keydown)="onKeyDown($event)"
1434
1533
  >
1435
- <ng-container *ngIf="!selectedItemTemplate">{{ label || 'empty' }}</ng-container>
1436
- <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: selectedOption }"></ng-container>
1534
+ <ng-container *ngIf="!selectedItemTemplate; else defaultPlaceholder">{{ label() === 'p-emptylabel' ? '&nbsp;' : label() || 'empty' }}</ng-container>
1535
+ <ng-container *ngTemplateOutlet="selectedItemTemplate; context: { $implicit: modelValue() }"></ng-container>
1536
+ <ng-template #defaultPlaceholder>
1537
+ <span *ngIf="label() === placeholder || (label() && !placeholder)">{{ label() === 'p-emptylabel' ? '&nbsp;' : placeholder }}</span>
1538
+ </ng-template>
1437
1539
  </span>
1438
- <span [ngClass]="{ 'p-dropdown-label p-inputtext p-placeholder': true, 'p-dropdown-label-empty': placeholder == null || placeholder.length === 0 }" *ngIf="!editable && label == null">{{ placeholder || 'empty' }}</span>
1439
1540
  <input
1541
+ *ngIf="editable"
1440
1542
  #editableInput
1441
1543
  type="text"
1442
1544
  [attr.maxlength]="maxlength"
1443
- class="p-dropdown-label p-inputtext"
1444
- *ngIf="editable"
1545
+ [ngClass]="inputClass"
1445
1546
  [disabled]="disabled"
1446
- [attr.placeholder]="placeholder"
1447
1547
  aria-haspopup="listbox"
1548
+ [attr.placeholder]="placeholder"
1448
1549
  [attr.aria-expanded]="overlayVisible"
1449
- (input)="onEditableInputChange($event)"
1450
- (focus)="onEditableInputFocus($event)"
1550
+ (input)="onEditableInput($event)"
1551
+ (keydown)="onKeyDown($event)"
1552
+ (focus)="onInputFocus($event)"
1451
1553
  (blur)="onInputBlur($event)"
1452
1554
  />
1453
-
1454
1555
  <ng-container *ngIf="isVisibleClearIcon">
1455
- <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" />
1456
- <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate">
1556
+ <TimesIcon [styleClass]="'p-dropdown-clear-icon'" (click)="clear($event)" *ngIf="!clearIconTemplate" [attr.data-pc-section]="'clearicon'" />
1557
+ <span class="p-dropdown-clear-icon" (click)="clear($event)" *ngIf="clearIconTemplate" [attr.data-pc-section]="'clearicon'">
1457
1558
  <ng-template *ngTemplateOutlet="clearIconTemplate"></ng-template>
1458
1559
  </span>
1459
1560
  </ng-container>
1460
1561
 
1461
- <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible">
1562
+ <div class="p-dropdown-trigger" role="button" aria-label="dropdown trigger" aria-haspopup="listbox" [attr.aria-expanded]="overlayVisible" [attr.data-pc-section]="'trigger'">
1462
1563
  <ng-container *ngIf="!dropdownIconTemplate">
1463
1564
  <span class="p-dropdown-trigger-icon" *ngIf="dropdownIcon" [ngClass]="dropdownIcon"></span>
1464
1565
  <ChevronDownIcon *ngIf="!dropdownIcon" [styleClass]="'p-dropdown-trigger-icon'" />
@@ -1483,6 +1584,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1483
1584
  >
1484
1585
  <ng-template pTemplate="content">
1485
1586
  <div [ngClass]="'p-dropdown-panel p-component'" [ngStyle]="panelStyle" [class]="panelStyleClass">
1587
+ <span
1588
+ #firstHiddenFocusableElementOnOverlay
1589
+ role="presentation"
1590
+ [attr.aria-hidden]="true"
1591
+ class="p-hidden-accessible p-hidden-focusable"
1592
+ [attr.tabindex]="0"
1593
+ (focus)="onFirstHiddenFocus($event)"
1594
+ [attr.data-p-hidden-focusable]="true"
1595
+ ></span>
1486
1596
  <ng-container *ngTemplateOutlet="headerTemplate"></ng-container>
1487
1597
  <div class="p-dropdown-header" *ngIf="filter" (click)="$event.stopPropagation()">
1488
1598
  <ng-container *ngIf="filterTemplate; else builtInFilterElement">
@@ -1494,14 +1604,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1494
1604
  #filter
1495
1605
  type="text"
1496
1606
  autocomplete="off"
1497
- [value]="filterValue || ''"
1607
+ [value]="_filterValue() || ''"
1498
1608
  class="p-dropdown-filter p-inputtext p-component"
1499
1609
  [attr.placeholder]="filterPlaceholder"
1500
- (keydown.enter)="$event.preventDefault()"
1501
- (keydown)="onKeydown($event, false)"
1610
+ [attr.aria-owns]="id + '_list'"
1502
1611
  (input)="onFilterInputChange($event)"
1503
1612
  [attr.aria-label]="ariaFilterLabel"
1504
- [attr.aria-activedescendant]="overlayVisible ? 'p-highlighted-option' : labelId"
1613
+ [attr.aria-activedescendant]="focusedOptionId"
1614
+ (keydown)="onFilterKeyDown($event)"
1615
+ (blur)="onFilterBlur($event)"
1505
1616
  />
1506
1617
  <SearchIcon *ngIf="!filterIconTemplate" [styleClass]="'p-dropdown-filter-icon'" />
1507
1618
  <span *ngIf="filterIconTemplate" class="p-dropdown-filter-icon">
@@ -1514,7 +1625,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1514
1625
  <p-scroller
1515
1626
  *ngIf="virtualScroll"
1516
1627
  #scroller
1517
- [items]="optionsToDisplay"
1628
+ [items]="visibleOptions()"
1518
1629
  [style]="{ height: scrollHeight }"
1519
1630
  [itemSize]="virtualScrollItemSize || _itemSize"
1520
1631
  [autoSize]="true"
@@ -1532,35 +1643,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1532
1643
  </ng-container>
1533
1644
  </p-scroller>
1534
1645
  <ng-container *ngIf="!virtualScroll">
1535
- <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: optionsToDisplay, options: {} }"></ng-container>
1646
+ <ng-container *ngTemplateOutlet="buildInItems; context: { $implicit: visibleOptions(), options: {} }"></ng-container>
1536
1647
  </ng-container>
1537
1648
 
1538
1649
  <ng-template #buildInItems let-items let-scrollerOptions="options">
1539
- <ul #items [attr.id]="listId" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1540
- <ng-container *ngIf="group">
1541
- <ng-template ngFor let-optgroup [ngForOf]="items">
1542
- <li class="p-dropdown-item-group" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1543
- <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(optgroup) || 'empty' }}</span>
1544
- <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: optgroup }"></ng-container>
1650
+ <ul #items [attr.id]="id + '_list'" class="p-dropdown-items" [ngClass]="scrollerOptions.contentStyleClass" [style]="scrollerOptions.contentStyle" role="listbox">
1651
+ <ng-template ngFor let-option [ngForOf]="items" let-i="index">
1652
+ <ng-container *ngIf="option.group">
1653
+ <li class="p-dropdown-item-group" [attr.id]="id + '_' + getOptionIndex(i, scrollerOptions)" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }" role="option">
1654
+ <span *ngIf="!groupTemplate">{{ getOptionGroupLabel(option.optionGroup) }}</span>
1655
+ <ng-container *ngTemplateOutlet="groupTemplate; context: { $implicit: option.optionGroup }"></ng-container>
1545
1656
  </li>
1546
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: getOptionGroupChildren(optgroup), selectedOption: selectedOption }"></ng-container>
1547
- </ng-template>
1548
- </ng-container>
1549
- <ng-container *ngIf="!group">
1550
- <ng-container *ngTemplateOutlet="itemslist; context: { $implicit: items, selectedOption: selectedOption }"></ng-container>
1551
- </ng-container>
1552
- <ng-template #itemslist let-options let-selectedOption="selectedOption">
1553
- <ng-template ngFor let-option let-i="index" [ngForOf]="options">
1657
+ </ng-container>
1658
+ <ng-container *ngIf="!option.group">
1554
1659
  <p-dropdownItem
1660
+ [id]="id + '_' + getOptionIndex(i, scrollerOptions)"
1555
1661
  [option]="option"
1556
- [selected]="selectedOption == option"
1662
+ [selected]="isSelected(option)"
1557
1663
  [label]="getOptionLabel(option)"
1558
1664
  [disabled]="isOptionDisabled(option)"
1559
- (onClick)="onItemClick($event)"
1560
1665
  [template]="itemTemplate"
1666
+ [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)"
1667
+ [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))"
1668
+ [ariaSetSize]="ariaSetSize"
1669
+ (onClick)="onOptionSelect($event, option)"
1670
+ (onMouseEnter)="onOptionMouseEnter($event, getOptionIndex(i, scrollerOptions))"
1561
1671
  ></p-dropdownItem>
1562
- </ng-template>
1672
+ </ng-container>
1563
1673
  </ng-template>
1674
+
1564
1675
  <li *ngIf="filterValue && isEmpty()" class="p-dropdown-empty-message" [ngStyle]="{ height: scrollerOptions.itemSize + 'px' }">
1565
1676
  <ng-container *ngIf="!emptyFilterTemplate && !emptyTemplate; else emptyFilter">
1566
1677
  {{ emptyFilterMessageLabel }}
@@ -1585,8 +1696,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1585
1696
  class: 'p-element p-inputwrapper',
1586
1697
  '[class.p-inputwrapper-filled]': 'filled',
1587
1698
  '[class.p-inputwrapper-focus]': 'focused || overlayVisible'
1588
- }, providers: [DROPDOWN_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;visibility:hidden}input.p-dropdown-label{cursor:default}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"] }]
1589
- }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }]; }, propDecorators: { scrollHeight: [{
1699
+ }, providers: [DROPDOWN_VALUE_ACCESSOR], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, styles: ["@layer primeng{.p-dropdown{display:inline-flex;cursor:pointer;position:relative;-webkit-user-select:none;user-select:none}.p-dropdown-clear-icon{position:absolute;top:50%;margin-top:-.5rem}.p-dropdown-trigger{display:flex;align-items:center;justify-content:center;flex-shrink:0}.p-dropdown-label{display:block;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:1%;text-overflow:ellipsis;cursor:pointer}.p-dropdown-label-empty{overflow:hidden;opacity:0}input.p-dropdown-label{cursor:default}.p-dropdown .p-dropdown-panel{min-width:100%}.p-dropdown-panel{position:absolute;top:0;left:0}.p-dropdown-items-wrapper{overflow:auto}.p-dropdown-item{cursor:pointer;font-weight:400;white-space:nowrap;position:relative;overflow:hidden}.p-dropdown-item-group{cursor:auto}.p-dropdown-items{margin:0;padding:0;list-style-type:none}.p-dropdown-filter{width:100%}.p-dropdown-filter-container{position:relative}.p-dropdown-filter-icon{position:absolute;top:50%;margin-top:-.5rem}.p-fluid .p-dropdown{display:flex}.p-fluid .p-dropdown .p-dropdown-label{width:1%}}\n"] }]
1700
+ }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i3.FilterService }, { type: i3.PrimeNGConfig }]; }, propDecorators: { id: [{
1701
+ type: Input
1702
+ }], scrollHeight: [{
1590
1703
  type: Input
1591
1704
  }], filter: [{
1592
1705
  type: Input
@@ -1622,6 +1735,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1622
1735
  type: Input
1623
1736
  }], filterBy: [{
1624
1737
  type: Input
1738
+ }], filterFields: [{
1739
+ type: Input
1625
1740
  }], autofocus: [{
1626
1741
  type: Input
1627
1742
  }], resetFilterOnHide: [{
@@ -1676,6 +1791,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1676
1791
  type: Input
1677
1792
  }], tooltipStyleClass: [{
1678
1793
  type: Input
1794
+ }], focusOnHover: [{
1795
+ type: Input
1796
+ }], selectOnFocus: [{
1797
+ type: Input
1798
+ }], autoOptionFocus: [{
1799
+ type: Input
1679
1800
  }], autofocusFilter: [{
1680
1801
  type: Input
1681
1802
  }], disabled: [{
@@ -1718,9 +1839,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1718
1839
  }], filterViewChild: [{
1719
1840
  type: ViewChild,
1720
1841
  args: ['filter']
1721
- }], accessibleViewChild: [{
1842
+ }], focusInputViewChild: [{
1722
1843
  type: ViewChild,
1723
- args: ['in']
1844
+ args: ['focusInput']
1724
1845
  }], editableInputViewChild: [{
1725
1846
  type: ViewChild,
1726
1847
  args: ['editableInput']
@@ -1733,6 +1854,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.0.2", ngImpor
1733
1854
  }], overlayViewChild: [{
1734
1855
  type: ViewChild,
1735
1856
  args: ['overlay']
1857
+ }], firstHiddenFocusableElementOnOverlay: [{
1858
+ type: ViewChild,
1859
+ args: ['firstHiddenFocusableElementOnOverlay']
1736
1860
  }], templates: [{
1737
1861
  type: ContentChildren,
1738
1862
  args: [PrimeTemplate]